AFNetworking是基于NSURLSession實現(xiàn)的?;叵胍幌翹SURLSession的使用方式:
創(chuàng)建NSURLSessionConfig對象
用之前創(chuàng)建的NSURLSessionConfig對象創(chuàng)建配置NSURLSession對象。
用NSURLSession對象創(chuàng)建對應(yīng)的task對象 并用resume方法執(zhí)行之。
用delegate方法或completion block 響應(yīng)網(wǎng)絡(luò)事件及數(shù)據(jù)。
對應(yīng)于每次網(wǎng)絡(luò)會話(這里可以簡單理解為一個網(wǎng)頁),對應(yīng)一個NSURLSession對象,而每個會話,可以生成若干task對象用于數(shù)據(jù)的交互。
而在AFNet中, AFURLSessionManager作為核心類,封裝并提供了上述網(wǎng)絡(luò)交互功能。
AFURLSessionManager組成
AFNet運用了組合的設(shè)計模式,將不同功能搭建成AFURLSessionManager的功能。
AFURLSessionManager的主要屬性:
/**
The managed session.
*/
@property (readonly, nonatomic, strong) NSURLSession *session;
/**
The operation queue on which delegate callbacks are run.
*/
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
/**
Responses sent from the server in data tasks created with dataTaskWithRequest:success:failure: and run using the GET / POST / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of AFJSONResponseSerializer.
@warning responseSerializer must not be nil.
*/
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
///-------------------------------
/// @name Managing Security Policy
///-------------------------------
/**
The security policy used by created session to evaluate server trust for secure connections. AFURLSessionManager uses the defaultPolicy unless otherwise specified.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
if !TARGET_OS_WATCH
///--------------------------------------
/// @name Monitoring Network Reachability
///--------------------------------------
/**
The network reachability manager. AFURLSessionManager uses the sharedManager by default.
*/
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
endif
///----------------------------
/// @name Getting Session Tasks
///----------------------------
/**
The data, upload, and download tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
/**
The data tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
/**
The upload tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
/**
The download tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
///-------------------------------
/// @name Managing Callback Queues
///-------------------------------
/**
The dispatch queue for completionBlock. If NULL (default), the main queue is used.
*/
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
/**
The dispatch group for completionBlock. If NULL (default), a private dispatch group is used.
*/
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
AFNet的注釋很詳細,其屬性可以作如下分類
AFURLSessionManager所管理的Session對象
@property (readonly, nonatomic, strong) NSURLSession *session;
delegate所返回的NSOperationQueue
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
解析網(wǎng)絡(luò)返回數(shù)據(jù)的對象(遵循AFURLResponseSerialization協(xié)議)
@property (nonatomic, strong) id responseSerializer;
用于處理網(wǎng)絡(luò)連接安全處理策略的AFSecurityPolicy對象
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
用于檢測網(wǎng)絡(luò)數(shù)據(jù)的AFNetworkReachabilityManager對象
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
當前的Session task
*tasks;
*dataTasks;
*uploadTasks;
*downloadTasks;
設(shè)置Call back隊列
在這里除了能設(shè)置Session的completion block外(默認為main block),還可以設(shè)置completion group。
看過這些分類,是不是覺得AFURLSessionManager也不是多么復雜了?確實,AFNet本就是一套簡潔的網(wǎng)絡(luò)框架,功能強大而結(jié)構(gòu)清晰。
下面,我們就一起看一看,利用AFURLSessionManager是如何完成一次簡單的網(wǎng)絡(luò)請求的。
運用AFURLSessionManager完成網(wǎng)絡(luò)請求
運用AFRULSessionManager獲取網(wǎng)絡(luò)數(shù)據(jù),僅需如下幾個步驟:
// step1. 初始化AFURLSessionManager對象
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
// step2. 獲取AFURLSessionManager的task對象
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Get Net data success!");
}
}];
// step3. 發(fā)動task
[dataTask resume];
OK,簡單的三步,就完成了對網(wǎng)絡(luò)數(shù)據(jù)的請求。
下面我們就一步步分析,這三步背后AFNet的源代碼是如何實現(xiàn)的。
初始化AFURLSessionManager
要進行網(wǎng)絡(luò)請求,第一步就是初始化AFURLSessionManager,調(diào)用函數(shù)
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration
1
該函數(shù)很簡單,只有一個NSURLSessionConfiguration用來配置AFURLSessionManager所管理的NSURLSession對象。
它的實現(xiàn)代碼如下:
(instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
// =============== 設(shè)置NSURLSession ===============
// 若configuration為nil,則采用默認defaultSessionConfiguration
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
// session 的delegate callback queue, 最大并發(fā)為1
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
// 初始化所管理的session
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
// =============== 設(shè)置response 數(shù)據(jù)序列化 ===============
self.responseSerializer = [AFJSONResponseSerializer serializer];
// =============== 設(shè)置網(wǎng)絡(luò)安全策略 ===============
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
// =============== 設(shè)置網(wǎng)絡(luò)狀態(tài)監(jiān)控Manager(注意這里是一個全局單例實現(xiàn)) ===============
if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
endif
// =============== 設(shè)置存儲NSURL task與AFURLSessionManagerTaskDelegate的詞典(重點,在AFNet中,每一個task都會被匹配一個AFURLSessionManagerTaskDelegate 來做task的delegate事件處理) ===============
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
// =============== 設(shè)置AFURLSessionManagerTaskDelegate 詞典的鎖,確保詞典在多線程訪問時的線程安全===============
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
// =============== 為所管理的session的所有task設(shè)置完成塊(這里不是很明白,既然是初始化函數(shù),那么應(yīng)該沒有任何task在運行才是,怎么需要在這里設(shè)置完成塊呢???)===============
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
// =============== 返回初始化好的self ===============
return self;
}
這就是AFURLSessionManager的初始化函數(shù),主要是對其屬性進行初始化,要注意的是它的私有屬性
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
@property (readwrite, nonatomic, strong) NSLock *lock;
AFURLSessionManager會為每一個所管理的task對應(yīng)創(chuàng)建一個AFURLSessionManagerTaskDelegate對象,Manager會交ManagerTaskDelegate對象由來具體處理各個task事物,從而實現(xiàn)了同一個AFURLSessionManager對多個task的管理。
生成AFURLSessionManager的task對象
當初始化好AFURLSessionManager后,就需要獲取一個代表我們當前網(wǎng)絡(luò)請求的task了:
/**
Creates an NSURLSessionDataTask with the specified request.
@param request The HTTP request for the request.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
當然還可以獲取download task 和upload task, 這里我們僅分析最簡單的data task。
其實現(xiàn)如下:
return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
1
僅一行代碼,調(diào)用自身另一方法:
-
(NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
上述方法完成了兩件事情:
- 生成一個data task對象,并返回。
- 為該data task對象生成一個匹配的AFURLSessionManagerTaskDelegate對象,并關(guān)聯(lián)之。
對于功能1,沒什么多說的,就是這里AFNet為了避免iOS 8.0以下版本中偶發(fā)的taskIdentifiers不唯一的bug,AFNet使用了
static void url_session_manager_create_task_safely(dispatch_block_t block) {
if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
// Fix of bug
// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
dispatch_sync(url_session_manager_creation_queue(), block);
} else {
block();
}
}
函數(shù)創(chuàng)建task對象。
其實現(xiàn)應(yīng)該是因為iOS 8.0以下版本中會并發(fā)地創(chuàng)建多個task對象,而同步有沒有做好,導致taskIdentifiers 不唯一…
對于功能二,AFNet為每一個task生成對應(yīng)的task delegate對象,我們則應(yīng)該重點了解一下。
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
// 創(chuàng)建AFURLSessionManagerTaskDelegate對象
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
// AFURLSessionManagerTaskDelegate與AFURLSessionManager建立相互關(guān)系
delegate.manager = self;
// 設(shè)置AF delegate的完成塊為用戶傳入的完成塊
delegate.completionHandler = completionHandler;
// 設(shè)置dataTask的taskDescription
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
// ***** 將AF delegate對象與 dataTask建立關(guān)系
[self setDelegate:delegate forTask:dataTask];
// 設(shè)置AF delegate的上傳進度,下載進度塊。
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
AFNet通過封裝AFURLSessionManagerTaskDelegate對象,對每個task 進行管理,而AFURLSessionManager僅需要管理建立task 與AF delegate的詞典即可,實現(xiàn)了AFURLSessionManager功能的下放。
那么我們這里重點看一下,AF delegate與task是如何建立關(guān)系的:
[self setDelegate:delegate forTask:dataTask];
實現(xiàn):
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
// 加鎖,確保詞典的線程安全
[self.lock lock];
// 將AF delegate放入以taskIdentifier標記的詞典中(同一個NSURLSession中的taskIdentifier是唯一的)
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 為AF delegate 設(shè)置task 的progress監(jiān)聽
[delegate setupProgressForTask:task];
[self addNotificationObserverForTask:task];
// 詞典操作完畢,解鎖
[self.lock unlock];
}
AFURLSessionManager會將每個AF delegate放入其詞典中,同時,AF delegate會監(jiān)聽每個task的進度,這是通過
[delegate setupProgressForTask:task];
實現(xiàn)的。我們繼續(xù)看 AF delegate 是如何監(jiān)聽task的各種進度的:
pragma mark - NSProgress Tracking
-
(void)setupProgressForTask:(NSURLSessionTask *)task {
__weak typeof(task) weakTask = task;self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
[self.uploadProgress setCancellable:YES];
[self.uploadProgress setCancellationHandler:^{
typeof(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.uploadProgress setPausable:YES];
[self.uploadProgress setPausingHandler:^{
typeof(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.uploadProgress setResumingHandler:^{
typeof(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}[self.downloadProgress setCancellable:YES];
[self.downloadProgress setCancellationHandler:^{
typeof(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.downloadProgress setPausable:YES];
[self.downloadProgress setPausingHandler:^{
typeof(weakTask) strongTask = weakTask;
[strongTask suspend];
}];if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.downloadProgress setResumingHandler:^{
typeof(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}// 這里為什么要用NSStringFromSelector 而不直接使用NSString???
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
options:NSKeyValueObservingOptionNew
context:NULL];[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
options:NSKeyValueObservingOptionNew
context:NULL];[self.downloadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.uploadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
上面的代碼可以分為兩個部分,
- 設(shè)置AF delegate的uploadProgress 和 downloadProgress。(注意為了防止對block對象截取產(chǎn)生的循環(huán)引用,將傳入的task設(shè)置為了weak。但是這里的循環(huán)引用在哪里呢??? 其實這里鑒于block所造成的一系列循環(huán)引用的問題,AFNet采取了一種防御式編程的方法,對于沒有必要在block中進行強引用的變量,一律采用弱引用。并且,當task置為nil后,block也沒有理由繼續(xù)strong引用task變量)
- 利用KVO, 監(jiān)聽task屬性及uploadProgress,downloadProgress屬性的變化,進一步監(jiān)聽task的數(shù)據(jù)傳輸進程。
看到了KVO,那我們就直接看其對應(yīng)的響應(yīng)函數(shù):
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([object isKindOfClass:[NSURLSessionTask class]]) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
self.downloadProgress.completedUnitCount = [change[@"new"] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
self.downloadProgress.totalUnitCount = [change[@"new"] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
self.uploadProgress.completedUnitCount = [change[@"new"] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
self.uploadProgress.totalUnitCount = [change[@"new"] longLongValue];
}
}
else if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
else if ([object isEqual:self.uploadProgress]) {
if (self.uploadProgressBlock) {
self.uploadProgressBlock(object);
}
}
}
很簡單,當監(jiān)控的Task屬性改變時,同時改變由AF delegate所管理持有的Progress對象的屬性。
同時,當AF delegate的Progress對象屬性改變時,調(diào)用對應(yīng)的progress block。
NSURLSessionDelegate 的響應(yīng)
因為AFURLSessionManager所管理的NSURLSession對象的delegate被設(shè)置為AFURLSessionManager自身,因此所有的NSURLSessionDelegate回調(diào)方法的目的地都是AFURLSessionManager,而AFURLSessionManager又會根據(jù)是否需要具體處理,會將屬于AF delegate要響應(yīng)的delegate,傳遞到對應(yīng)的AF delegate去。
AFURLSessionManager 和 AFURLSessionManagerTaskDelegate 相應(yīng)的delegate回調(diào)方法如下:
AFURLSessionManager 需要處理的NSURLSessionDelegate:
這里寫圖片描述
AFURLSessionManagerTaskDelegate 需要處理的NSURLSessionDelegate:
這里寫圖片描述
當AFURLSessionManager 覺得應(yīng)該有AF delegate來處理該事件時,會取出對應(yīng)task的delegate,并將該事件原封不動的傳遞到delegate。
其實細看AF delegate所實現(xiàn)的NSURLSessionDelegate也不多,僅三條:
-URLSession:task:didCompleteWithError:
-URLSession:dataTask:didReceiveData:
-URLSession:downloadTask:didFinishDownloadingToURL:
可以看出,屬于AF task delegate處理的回調(diào),兩條是對于completion的處理,另一條則是對于每個task,分別接受并記錄其receive data。
而AFURLSessionManager對于NSSession的回調(diào)處理相對簡單,不外乎兩步:
- 如果有對應(yīng)的user block,則將當前NSSession block傳遞至user block(此處可能會利用user block的返回值,來繼續(xù)下一步操作)。
- 如果需要AF task delegate處理,則將該回調(diào)事件傳給相應(yīng)的AF task delegate。
我們可以看下面幾個例子:
-
(void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest *))completionHandler
{
NSURLRequest *redirectRequest = request;
// step1. 看是否有對應(yīng)的user block
if (self.taskWillPerformHTTPRedirection) {
redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
}if (completionHandler) {
// step2. 運用user block返回值或是原始值,使NSSession事件繼續(xù)
completionHandler(redirectRequest);
}
} -
(void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
// step1. 應(yīng)交由AF task delegate處理的事件,取出對應(yīng)AF task delegate,
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];// delegate may be nil when completing a task in the background
if (delegate) {
// step2. 將事件交由AF task delegate處理
[delegate URLSession:session task:task didCompleteWithError:error];
// NOTE: 此處是session task最終的回調(diào)函數(shù),task不會再返回任何信息。因此刪除對應(yīng)的AF task delegate
[self removeDelegateForTask:task];
}
// step3. 若有對應(yīng)的user block,則調(diào)用之
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
AFURLSessionManager 與 AFURLSessionManagerTaskDelegate 的分工
到這里我們可以想一想,既然NSURLSession的delegate是AFURLSessionManager對象,那么為什么不在AFURLSessionManager中處理所有的事件回調(diào),搞出來一個AFURLSessionManagerTaskDelegate干什么?
我們知道,NSURLSession的回調(diào)有很多,而當我們啟動一個task,真正想要獲取的信息是什么呢?就是網(wǎng)絡(luò)請求最終所返回的數(shù)據(jù)(我所進行的網(wǎng)絡(luò)操作成功或是失敗,服務(wù)器為我返回的數(shù)據(jù))唄! 其它的回調(diào),什么認證質(zhì)詢,task需要新的body stream,什么request即將重定向, 統(tǒng)統(tǒng)都是浮云,都是為了我們能夠最終獲取到服務(wù)器返回的數(shù)據(jù)所服務(wù)的。
另外我們也想要知道我們的網(wǎng)絡(luò)請求的進度。
總結(jié)為兩點:
- 獲取最終返回數(shù)據(jù)
- 獲知當前請求的進度
于是,AFNetWorking 便在紛繁復雜的回調(diào)處理中,特意抽象出AFURLSessionManagerTaskDelegate,用于應(yīng)付網(wǎng)絡(luò)返回數(shù)據(jù)的處理(包括保存中間值,序列化返回值,錯誤處理)和網(wǎng)絡(luò)請求進度。
這樣做可以使代碼結(jié)構(gòu)更分明,邏輯更清晰。
這在AFURLSessionManagerTaskDelegate的聲明中也可以看出一二, 其屬性按功能分類就兩種,一種用來保存服務(wù)器返回數(shù)據(jù)及completion回調(diào),另一種就是反應(yīng)當前網(wǎng)絡(luò)處理進度:
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
@property (nonatomic, weak) AFURLSessionManager *manager;
@property (nonatomic, strong) NSMutableData *mutableData; // 保存服務(wù)器返回的數(shù)據(jù)
@property (nonatomic, strong) NSProgress *uploadProgress; // 上傳進度
@property (nonatomic, strong) NSProgress *downloadProgress; // 下載進度
@property (nonatomic, copy) NSURL *downloadFileURL; // 下載文件目的存儲地址
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
@end