版本記錄
| 版本號 | 時間 |
|---|---|
| V1.0 | 2018.02.28 |
前言
我們做APP發(fā)起網絡請求,都離不開一個非常有用的框架AFNetworking,可以說這個框架的知名度已經超過了蘋果的底層網絡請求部分,很多人可能不知道蘋果底層是如何發(fā)起網絡請求的,但是一定知道
AFNetworking,接下來幾篇我們就一起詳細的解析一下這個框架。感興趣的可以看上面寫的幾篇。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請求實現之NSURLSessionDataTask實例化(一)
3. AFNetworking源碼探究(三) —— GET請求實現之任務進度設置和通知監(jiān)聽(一)
回顧
上一篇主要包括AFURLSessionManagerTaskDelegate代理為任務設置進度和AFURLSessionManager為任務添加通知監(jiān)聽。這一篇主要說一下自定義類AFURLSessionManagerTaskDelegate和AFURLSessionManager中有關代理的轉發(fā)邏輯,這一篇的重點就在于這個轉發(fā)邏輯思想的理解,代碼的意義其次,讀完你就會感到大神寫代碼的高質量。
重寫respondsToSelector方法
主要對應下面這端代碼。
- (BOOL)respondsToSelector:(SEL)selector {
if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
return self.taskWillPerformHTTPRedirection != nil;
} else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
return self.dataTaskDidReceiveResponse != nil;
} else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
return self.dataTaskWillCacheResponse != nil;
} else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
return self.didFinishEventsForBackgroundURLSession != nil;
}
return [[self class] instancesRespondToSelector:selector];
}
重寫respondsToSelector的作用就是判斷NSURLSession那幾個代理是否能響應,如果響應了就去調用。復寫了selector的方法,這幾個方法是在本類有實現的,但是如果外面的Block沒賦值的話,則返回NO,相當于沒有實現。
這樣如果沒實現這些我們自定義的Block也不會去回調這些代理。因為本身某些代理,只執(zhí)行了這些自定義的Block,如果Block都沒有賦值,那我們調用代理也沒有任何意義。
block的屬性和值的設置
上面說到了block下面我們看一下定義的block的屬性。
@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;
typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request);
typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session);
typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task);
typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error);
typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response);
typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask);
typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data);
typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse);
typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
下面看一下這些屬性的值的設定。在.h文件中有接口,并在.m中是實現,這里就舉一個例子,如下:
/**
Sets a block to be executed when the managed session becomes invalid, as handled by the `NSURLSessionDelegate` method `URLSession:didBecomeInvalidWithError:`.
@param block A block object to be executed when the managed session becomes invalid. The block has no return value, and takes two arguments: the session, and the error related to the cause of invalidation.
*/
- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;
- (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block {
self.sessionDidBecomeInvalid = block;
}
這么做的目的是為了我們這些用戶使用起來方便,調用set方法去設置這些Block,能很清晰的看到Block的各個參數與返回值。
代理轉發(fā)思想
我先整體和大家說一下AFN中有關代理的轉發(fā)邏輯。
AFURLSessionManager中是有關NSURLSession的代理,主要包含下面的幾個代理的實現。

上面的幾個代理是什么關系,相信看過我寫的SDWebImage的源碼分析的應該很清楚,他們是繼承的關系,就不多說了。而AFURLSessionManagerTaskDelegate實現了三個代理方法。

AFUrlSessionManager對這一大堆代理做了一些公共的處理,而轉發(fā)到AF自定義代理的3條,則負責把每個task對應的數據回調出去。
那么是如何轉發(fā)過去的呢,簡單的調用就是這樣的。
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
通過[delegate URLSession:session task:task didCompleteWithError:error];就轉發(fā)了過去。這里首先就是從字典中找到該任務對應的代理AFURLSessionManagerTaskDelegate對象,然后就是轉發(fā)到自定義代理中。
大家如果讀過SDWebImage的源碼的話,就應該明白,那里也用到了代理的轉發(fā),可見,這種轉發(fā)思想有它的優(yōu)點,值得我們去學習。
后記
本篇文章主要介紹了一種代理的轉發(fā)思想,從
NSURLSession原生的代理轉發(fā)代理到AFURLSessionManagerTaskDelegate自定義的代理中。這一篇最主要的就是學習和掌握這種思想。
