AFNetworking是基于NSURLSession實(shí)現(xiàn)的。回想一下NSURLSession的使用方式:
創(chuàng)建NSURLSessionConfig對(duì)象
用之前創(chuàng)建的NSURLSessionConfig對(duì)象創(chuàng)建配置NSURLSession對(duì)象。
用NSURLSession對(duì)象創(chuàng)建對(duì)應(yīng)的task對(duì)象 并用resume方法執(zhí)行之。
用delegate方法或completion block 響應(yīng)網(wǎng)絡(luò)事件及數(shù)據(jù)。
對(duì)應(yīng)于每次網(wǎng)絡(luò)會(huì)話(這里可以簡(jiǎn)單理解為一個(gè)網(wǎng)頁),對(duì)應(yīng)一個(gè)NSURLSession對(duì)象,而每個(gè)會(huì)話,可以生成若干task對(duì)象用于數(shù)據(jù)的交互。
而在AFNet中, AFURLSessionManager作為核心類,封裝并提供了上述網(wǎng)絡(luò)交互功能。
AFURLSessionManager組成
AFNet運(yùn)用了組合的設(shè)計(jì)模式,將不同功能搭建成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的注釋很詳細(xì),其屬性可以作如下分類
AFURLSessionManager所管理的Session對(duì)象
@property (readonly, nonatomic, strong) NSURLSession *session;
delegate所返回的NSOperationQueue
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
解析網(wǎng)絡(luò)返回?cái)?shù)據(jù)的對(duì)象(遵循AFURLResponseSerialization協(xié)議)
@property (nonatomic, strong) id responseSerializer;
用于處理網(wǎng)絡(luò)連接安全處理策略的AFSecurityPolicy對(duì)象
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
用于檢測(cè)網(wǎng)絡(luò)數(shù)據(jù)的AFNetworkReachabilityManager對(duì)象
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
當(dāng)前的Session task
*tasks;
*dataTasks;
*uploadTasks;
*downloadTasks;
設(shè)置Call back隊(duì)列
在這里除了能設(shè)置Session的completion block外(默認(rèn)為main block),還可以設(shè)置completion group。
看過這些分類,是不是覺得AFURLSessionManager也不是多么復(fù)雜了?確實(shí),AFNet本就是一套簡(jiǎn)潔的網(wǎng)絡(luò)框架,功能強(qiáng)大而結(jié)構(gòu)清晰。
下面,我們就一起看一看,利用AFURLSessionManager是如何完成一次簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求的。
運(yùn)用AFURLSessionManager完成網(wǎng)絡(luò)請(qǐng)求
運(yùn)用AFRULSessionManager獲取網(wǎng)絡(luò)數(shù)據(jù),僅需如下幾個(gè)步驟:
// step1. 初始化AFURLSessionManager對(duì)象
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
// step2. 獲取AFURLSessionManager的task對(duì)象
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ā)動(dòng)task
[dataTask resume];
OK,簡(jiǎn)單的三步,就完成了對(duì)網(wǎng)絡(luò)數(shù)據(jù)的請(qǐng)求。
下面我們就一步步分析,這三步背后AFNet的源代碼是如何實(shí)現(xiàn)的。
初始化AFURLSessionManager
要進(jìn)行網(wǎng)絡(luò)請(qǐng)求,第一步就是初始化AFURLSessionManager,調(diào)用函數(shù)
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration
1
該函數(shù)很簡(jiǎn)單,只有一個(gè)NSURLSessionConfiguration用來配置AFURLSessionManager所管理的NSURLSession對(duì)象。
它的實(shí)現(xiàn)代碼如下:
(instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
// =============== 設(shè)置NSURLSession ===============
// 若configuration為nil,則采用默認(rèn)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(注意這里是一個(gè)全局單例實(shí)現(xiàn)) ===============
if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
endif
// =============== 設(shè)置存儲(chǔ)NSURL task與AFURLSessionManagerTaskDelegate的詞典(重點(diǎn),在AFNet中,每一個(gè)task都會(huì)被匹配一個(gè)AFURLSessionManagerTaskDelegate 來做task的delegate事件處理) ===============
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
// =============== 設(shè)置AFURLSessionManagerTaskDelegate 詞典的鎖,確保詞典在多線程訪問時(shí)的線程安全===============
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
// =============== 為所管理的session的所有task設(shè)置完成塊(這里不是很明白,既然是初始化函數(shù),那么應(yīng)該沒有任何task在運(yùn)行才是,怎么需要在這里設(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ù),主要是對(duì)其屬性進(jìn)行初始化,要注意的是它的私有屬性
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
@property (readwrite, nonatomic, strong) NSLock *lock;
AFURLSessionManager會(huì)為每一個(gè)所管理的task對(duì)應(yīng)創(chuàng)建一個(gè)AFURLSessionManagerTaskDelegate對(duì)象,Manager會(huì)交ManagerTaskDelegate對(duì)象由來具體處理各個(gè)task事物,從而實(shí)現(xiàn)了同一個(gè)AFURLSessionManager對(duì)多個(gè)task的管理。
生成AFURLSessionManager的task對(duì)象
當(dāng)初始化好AFURLSessionManager后,就需要獲取一個(gè)代表我們當(dāng)前網(wǎng)絡(luò)請(qǐng)求的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;
當(dāng)然還可以獲取download task 和upload task, 這里我們僅分析最簡(jiǎn)單的data task。
其實(shí)現(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;
}
上述方法完成了兩件事情:
- 生成一個(gè)data task對(duì)象,并返回。
- 為該data task對(duì)象生成一個(gè)匹配的AFURLSessionManagerTaskDelegate對(duì)象,并關(guān)聯(lián)之。
對(duì)于功能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對(duì)象。
其實(shí)現(xiàn)應(yīng)該是因?yàn)閕OS 8.0以下版本中會(huì)并發(fā)地創(chuàng)建多個(gè)task對(duì)象,而同步有沒有做好,導(dǎo)致taskIdentifiers 不唯一…
對(duì)于功能二,AFNet為每一個(gè)task生成對(duì)應(yīng)的task delegate對(duì)象,我們則應(yīng)該重點(diǎn)了解一下。
- (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對(duì)象
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對(duì)象與 dataTask建立關(guān)系
[self setDelegate:delegate forTask:dataTask];
// 設(shè)置AF delegate的上傳進(jìn)度,下載進(jìn)度塊。
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
AFNet通過封裝AFURLSessionManagerTaskDelegate對(duì)象,對(duì)每個(gè)task 進(jìn)行管理,而AFURLSessionManager僅需要管理建立task 與AF delegate的詞典即可,實(shí)現(xiàn)了AFURLSessionManager功能的下放。
那么我們這里重點(diǎn)看一下,AF delegate與task是如何建立關(guān)系的:
[self setDelegate:delegate forTask:dataTask];
實(shí)現(xiàn):
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
// 加鎖,確保詞典的線程安全
[self.lock lock];
// 將AF delegate放入以taskIdentifier標(biāo)記的詞典中(同一個(gè)NSURLSession中的taskIdentifier是唯一的)
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 為AF delegate 設(shè)置task 的progress監(jiān)聽
[delegate setupProgressForTask:task];
[self addNotificationObserverForTask:task];
// 詞典操作完畢,解鎖
[self.lock unlock];
}
AFURLSessionManager會(huì)將每個(gè)AF delegate放入其詞典中,同時(shí),AF delegate會(huì)監(jiān)聽每個(gè)task的進(jìn)度,這是通過
[delegate setupProgressForTask:task];
實(shí)現(xiàn)的。我們繼續(xù)看 AF delegate 是如何監(jiān)聽task的各種進(jìn)度的:
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];
}
上面的代碼可以分為兩個(gè)部分,
- 設(shè)置AF delegate的uploadProgress 和 downloadProgress。(注意為了防止對(duì)block對(duì)象截取產(chǎn)生的循環(huán)引用,將傳入的task設(shè)置為了weak。但是這里的循環(huán)引用在哪里呢??? 其實(shí)這里鑒于block所造成的一系列循環(huán)引用的問題,AFNet采取了一種防御式編程的方法,對(duì)于沒有必要在block中進(jìn)行強(qiáng)引用的變量,一律采用弱引用。并且,當(dāng)task置為nil后,block也沒有理由繼續(xù)strong引用task變量)
- 利用KVO, 監(jiān)聽task屬性及uploadProgress,downloadProgress屬性的變化,進(jìn)一步監(jiān)聽task的數(shù)據(jù)傳輸進(jìn)程。
看到了KVO,那我們就直接看其對(duì)應(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)單,當(dāng)監(jiān)控的Task屬性改變時(shí),同時(shí)改變由AF delegate所管理持有的Progress對(duì)象的屬性。
同時(shí),當(dāng)AF delegate的Progress對(duì)象屬性改變時(shí),調(diào)用對(duì)應(yīng)的progress block。
NSURLSessionDelegate 的響應(yīng)
因?yàn)锳FURLSessionManager所管理的NSURLSession對(duì)象的delegate被設(shè)置為AFURLSessionManager自身,因此所有的NSURLSessionDelegate回調(diào)方法的目的地都是AFURLSessionManager,而AFURLSessionManager又會(huì)根據(jù)是否需要具體處理,會(huì)將屬于AF delegate要響應(yīng)的delegate,傳遞到對(duì)應(yīng)的AF delegate去。
AFURLSessionManager 和 AFURLSessionManagerTaskDelegate 相應(yīng)的delegate回調(diào)方法如下:
AFURLSessionManager 需要處理的NSURLSessionDelegate:
這里寫圖片描述
AFURLSessionManagerTaskDelegate 需要處理的NSURLSessionDelegate:
這里寫圖片描述
當(dāng)AFURLSessionManager 覺得應(yīng)該有AF delegate來處理該事件時(shí),會(huì)取出對(duì)應(yīng)task的delegate,并將該事件原封不動(dòng)的傳遞到delegate。
其實(shí)細(xì)看AF delegate所實(shí)現(xiàn)的NSURLSessionDelegate也不多,僅三條:
-URLSession:task:didCompleteWithError:
-URLSession:dataTask:didReceiveData:
-URLSession:downloadTask:didFinishDownloadingToURL:
可以看出,屬于AF task delegate處理的回調(diào),兩條是對(duì)于completion的處理,另一條則是對(duì)于每個(gè)task,分別接受并記錄其receive data。
而AFURLSessionManager對(duì)于NSSession的回調(diào)處理相對(duì)簡(jiǎn)單,不外乎兩步:
- 如果有對(duì)應(yīng)的user block,則將當(dāng)前NSSession block傳遞至user block(此處可能會(huì)利用user block的返回值,來繼續(xù)下一步操作)。
- 如果需要AF task delegate處理,則將該回調(diào)事件傳給相應(yīng)的AF task delegate。
我們可以看下面幾個(gè)例子:
-
(void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest *))completionHandler
{
NSURLRequest *redirectRequest = request;
// step1. 看是否有對(duì)應(yīng)的user block
if (self.taskWillPerformHTTPRedirection) {
redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
}if (completionHandler) {
// step2. 運(yùn)用user block返回值或是原始值,使NSSession事件繼續(xù)
completionHandler(redirectRequest);
}
} -
(void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
// step1. 應(yīng)交由AF task delegate處理的事件,取出對(duì)應(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不會(huì)再返回任何信息。因此刪除對(duì)應(yīng)的AF task delegate
[self removeDelegateForTask:task];
}
// step3. 若有對(duì)應(yīng)的user block,則調(diào)用之
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
AFURLSessionManager 與 AFURLSessionManagerTaskDelegate 的分工
到這里我們可以想一想,既然NSURLSession的delegate是AFURLSessionManager對(duì)象,那么為什么不在AFURLSessionManager中處理所有的事件回調(diào),搞出來一個(gè)AFURLSessionManagerTaskDelegate干什么?
我們知道,NSURLSession的回調(diào)有很多,而當(dāng)我們啟動(dòng)一個(gè)task,真正想要獲取的信息是什么呢?就是網(wǎng)絡(luò)請(qǐng)求最終所返回的數(shù)據(jù)(我所進(jìn)行的網(wǎng)絡(luò)操作成功或是失敗,服務(wù)器為我返回的數(shù)據(jù))唄! 其它的回調(diào),什么認(rèn)證質(zhì)詢,task需要新的body stream,什么request即將重定向, 統(tǒng)統(tǒng)都是浮云,都是為了我們能夠最終獲取到服務(wù)器返回的數(shù)據(jù)所服務(wù)的。
另外我們也想要知道我們的網(wǎng)絡(luò)請(qǐng)求的進(jìn)度。
總結(jié)為兩點(diǎn):
- 獲取最終返回?cái)?shù)據(jù)
- 獲知當(dāng)前請(qǐng)求的進(jìn)度
于是,AFNetWorking 便在紛繁復(fù)雜的回調(diào)處理中,特意抽象出AFURLSessionManagerTaskDelegate,用于應(yīng)付網(wǎng)絡(luò)返回?cái)?shù)據(jù)的處理(包括保存中間值,序列化返回值,錯(cuò)誤處理)和網(wǎng)絡(luò)請(qǐng)求進(jìn)度。
這樣做可以使代碼結(jié)構(gòu)更分明,邏輯更清晰。
這在AFURLSessionManagerTaskDelegate的聲明中也可以看出一二, 其屬性按功能分類就兩種,一種用來保存服務(wù)器返回?cái)?shù)據(jù)及completion回調(diào),另一種就是反應(yīng)當(dāng)前網(wǎng)絡(luò)處理進(jìn)度:
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
@property (nonatomic, weak) AFURLSessionManager *manager;
@property (nonatomic, strong) NSMutableData *mutableData; // 保存服務(wù)器返回的數(shù)據(jù)
@property (nonatomic, strong) NSProgress *uploadProgress; // 上傳進(jìn)度
@property (nonatomic, strong) NSProgress *downloadProgress; // 下載進(jìn)度
@property (nonatomic, copy) NSURL *downloadFileURL; // 下載文件目的存儲(chǔ)地址
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
@end