AFNetWorking源碼之AFURLSessionManager

1 概述

AFNetWorking基本上是全部iOS項目的標配。如今升級帶最新版的3.X了。得益於蘋果從NSURLConnection升級到NSURLSession,AFN也實現了api的簡化,同時功能卻一點沒少。咱們來看一下AFN3.X的目錄結構:html

  • AFNetWorking 這個文件是一個頭文件。啥也沒作,就是引入了其餘文件方便使用。git

  • AFURLSessionManager 這個文件是核心類,基本上經過它來實現了大部分核心功能。負責請求的創建、管理、銷燬、安全、請求重定向、請求重啓等各類功能。他主要實現了NSURLSessionNSRULSessionTask的封裝。github

  • AFHTTPSessionManager 這個文件是AFURLSessionManager的子類。主要實現了對HTTP請求的優化。api

  • AFURLRequestSerialization 這個主要用於請求頭的編碼解碼、序列化、優化處理、簡化請求拼接過程等。緩存

  • AFURLResponseSerialization 這個主要用於網絡返回數據的序列化、編碼解碼、序列化、數據處理等。安全

  • AFSecurityPolicy 這個主要用於請求的認證功能。好比https的認證模式等。網絡

  • AFNetworkReachabilityManager 這個主要用於監聽網絡請求狀態變化功能。session

首先說明,看AFN源碼以前必定要搞清楚NSURLSession系列的api,這樣能讓你事半功倍,具體能夠看AFNetWorking源碼之NSRULSession系列概述。在這篇文章裏,咱們主要講解AFURLSessionManager的實現原理和封裝過程。首先咱們經過一個簡單的網絡請求看一下他的基本用法(大部分都是非必須的,這裏爲了掩飾寫出來):app

- (IBAction)clickButton:(id)sender {
    //經過默認配置初始化Session
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    //設置網絡請求序列化對象
    AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
    [requestSerializer setValue:@"test" forHTTPHeaderField:@"requestHeader"];
    requestSerializer.timeoutInterval = 60;
    requestSerializer.stringEncoding = NSUTF8StringEncoding;
    //設置返回數據序列化對象
    AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
    manager.responseSerializer = responseSerializer;
    //網絡請求安全策略
    if (true) {
        AFSecurityPolicy *securityPolicy;
        securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
        securityPolicy.allowInvalidCertificates = false;
        securityPolicy.validatesDomainName = YES;
        manager.securityPolicy = securityPolicy;
    } else {
        manager.securityPolicy.allowInvalidCertificates = true;
        manager.securityPolicy.validatesDomainName = false;
    }
    //是否容許請求重定向
    if (true) {
        [manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest *(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request) {
            if (response) {
                return nil;
            }
            return request;
        }];
    }
    //監聽網絡狀態
    [manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        NSLog(@"%ld",(long)status);
    }];
    [manager.reachabilityManager startMonitoring];
    
    NSURL *URL = [NSURL URLWithString:bigPic];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress *downloadProgress){
        NSLog(@"下載進度:%lld",downloadProgress.completedUnitCount);
    } destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
        NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
        NSLog(@"fileURL:%@",[fileURL absoluteString]);
        return fileURL;
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
        self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:filePath]];
        NSLog(@"File downloaded to: %@", filePath);
    }];
    [downloadTask resume];
}

經過這個請求,咱們發現AFURLSessionManager要負責如下幾塊功能。異步

  • 初始化和管理NSURLSession,經過它來創建和管理各類Task。

  • 初始化和管理NSRULSessionTask,經過不一樣task來發送不一樣請求。

  • 管理各類認證功能、安全功能、請求重定向、數據處理。

  • 管理和組織每一個task的各類狀態管理和通知管理。不一樣task的回調處理。

  • 幫咱們管理和處理了NSRULSession系列api的各類代理方法。簡化了咱們的處理。

2 AFURLSessionManager的聲明分析

AFURLSessionManager根據一個指定的NSURLSessionConfiguration建立和管理一個NSURLSession對象。而且這個對象實現了<NSURLSessionTaskDelegate>, <NSURLSessionDataDelegate>, <NSURLSessionDownloadDelegate>, 和 <NSURLSessionDelegate>這幾個協議的協議方法。同時實現NSSecureCodingNSCopying來實現歸檔解檔和copy功能。

2.1 AFURLSessionManager的初始化api

這些api主要用於初始化、安全策略、網絡狀態監聽等:

interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
//指定的初始化方法、經過他來初始化一個Manager對象。
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration 
//AFURLSessionManager經過session來管理和建立網絡請求。一個manager就實現了對這個session的管理,他們是一一對應的關係。
@property (readonly, nonatomic, strong) NSURLSession *session;
//處理網絡請求回調的操做隊列,就是咱們初始化session的時候傳入的那個OperationQueue參數。若是不傳入,默認是MainOperationQueue。
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
//對返回數據的處理都經過這個屬性來處理,好比數據的提取、轉換等。默認是一個`AFJSONResponseSerializer`對象用JSON的方式解析。
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
//用於指定session的安全策略。用於處理信任主機和證書認證等。默認是`defaultPolicy`。
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
//觀測網絡狀態的變化,具體能夠看個人Demo用法。
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
@end

2.2 AFURLSessionManager獲取Task的api

這部分api主要是任務的建立、任務的分類、任務完成隊列處理、特殊狀況的任務從新建立等:

//當前session建立的全部Task,這個是下面三種task的總和。
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
//當前session建立的DataTask
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
//當前session建立的uploadTask
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
//當前session建立的downloadTask
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

//用於處理任務回調的GCD對象,默認是dispatch_main_queue。
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
//用於處理任務回調的GCD的group對象,若是不初始化、則一個默認的Group被使用。
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
//在iOS7的環境下,咱們經過background模式的session建立的uploadTask有時會是nil,若是這個屬性是yes,AFN會嘗試再次建立uploadTask。
@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;
//廢除manager對應的Session。經過傳入的參數來決定是否當即取消已經用session發出去的任務。
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;

2.3 AFURLSessionManager爲管理Task建立Block

AFURLSessionManager提供了不少建立Task的api。而且提供了不少處理Task的Block。應該說着幾個api就是AFN爲咱們提供的最大價值,他把全部delegate方法細節都處理好。直接提供給咱們一些最實用的api,咱們就不用去管理session系列繁瑣的delegate方法了。

//建立一個NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler;
//建立一個NSURLSessionDataTask,而且能獲取上傳或者下載進度
- (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;

//建立一個上傳Task,而且指定上傳文件的路徑。
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError  * _Nullable error))completionHandler;
////建立一個上傳Task,而且指定上傳的數據。
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(nullable NSData *)bodyData
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
//建立一個uploadTask,而後上傳數據
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
//新建一個download任務,destination表示的下載文件的緩存路徑
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                          destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
//繼續恢復一個download任務。resumeData參數表示的是恢復下載的時候初始化數據,好比前面已經下載好的部分數據。
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                             destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                       completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
//獲取指定Task的上傳進度
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
//獲取指定Task的下載進度
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;

注意:上面全部Task的progress都不在主線程、因此要在progress中作UI更新,都必須手動在主線程操做。

2.4 AFURLSessionManager設置各類狀況的代理回調

這些回調Block主要是用於處理網絡請求過程或者結束之後的數據處理、認證、通知、緩存等。咱們能夠經過設置這些Block來獲取或者檢測各類狀態。至關於就是鉤子函數。經過下面的這些Block,咱們基本能夠獲取請求過程當中的全部狀態以及須要作的各類處理。

//設置Session出錯或者無效的手的回調Block。這個Block主要在`NSURLSessionDelegate`代理的`URLSession:didBecomeInvalidWithError:`方法中執行。
- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block{
    
}
//當網絡請須要的認證信息好比用戶名密碼已經發送了的時候,就能夠經過這個Block來處理。這個Block是在`NSURLSessionDelegate`代理裏面的`URLSession:didReceiveChallenge:completionHandler:`方法中被執行。注意這個是針對Session
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block{
    
}
////當網絡請須要的認證信息好比用戶名密碼已經發送了的時候,就能夠經過這個Block來處理。這個Block是在`NSURLSessionTaskDelegate`代理裏面的`URLSession:task:didReceiveChallenge:completionHandler:`方法中被執行。注意這個是針對Task。
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block{
    
}
//當請求須要一個新的bodystream的時候,就能夠經過這個Block來設置。這個Block在`NSURLSessionTaskDelegate` 代理協議的`URLSession:task:needNewBodyStream:`方法裏面設置。
- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block{
    
}
//當一個網絡請求須要重定向的時候。就會調用這個Block。這個Block是在`NSURLSessionTaskDelegate`協議的`URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`方法中調用的。
- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block{
    
}
//能夠經過設置這個Block來獲取上傳進度。這個Block主要在`NSURLSessionTaskDelegate`協議的 `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`方法中調用.
- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block{
    
}
//設置一個Task完成之後執行的Block,這個Block在`NSURLSessionTaskDelegate`協議的 `URLSession:task:didCompleteWithError:`方法中執行。
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block{
    
}
//當接收到網絡請求返回之後,能夠調用這個Block。這個Block是在`NSURLSessionDataDelegate`協議的 `URLSession:dataTask:didReceiveResponse:completionHandler:`
- (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block{
    
}
//若是一個dataTask轉換爲downLoadTask之後,就能夠設置這個Block來調用。在`NSURLSessionDataDelegate` 協議的`URLSession:dataTask:didBecomeDownloadTask:`方法中調用。
- (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block{
    
}
//當dataTask接收到數據之後,能夠設置調用這個Block。具體在`NSURLSessionDataDelegate`協議的`URLSession:dataTask:didReceiveData:`方法。
- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block{
    
}
//設置一個Block來決定是否處理或者換成網絡請求緩存。具體在`NSURLSessionDataDelegate`協議的`URLSession:dataTask:willCacheResponse:completionHandler:`方法中。
- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block{
    
}
//當session全部的任務都發送出去之後,就能夠經過這個Block來獲取。具體在`NSURLSessionDataDelegate`協議的 `URLSessionDidFinishEventsForBackgroundURLSession:`方法中。
- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block{
    
}
//當一個downloadTask執行完畢之後,能夠經過這個Block來獲取下載信息,咱們能夠經過這個Block獲取下載文件的位置。具體在`NSURLSessionDownloadDelegate`協議的`URLSession:downloadTask:didFinishDownloadingToURL:`方法中被調用。
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable  (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block{
    
}
//能夠經過這個Block獲取一個downloadTask的下載進度。這個Block會在下載過程當中屢次被調用。具體是在`NSURLSessionDownloadDelegate`協議中的`URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`方法中被調用。
- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block{
    
}
//當一個downloadTask從新開始之後,咱們能夠經過這個Block獲取fileOffSet等信息獲取已經下載的部分以及總共有多少要下載。具體是在`NSURLSessionDownloadDelegate`協議的`URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`方法中被調用。
- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block{
    
}

除了上面的部分,AFURLSessionManager的頭文件還提供了不少notification的聲明。經過這些通知,咱們能夠獲取Task是否開始、是否完成、是否掛起、是否無效等各類通知。具體能夠去文件裏看。

3 AFURLSessionManager的實現分析

AFURLSessionManager.m文件裏面除了有AFURLSessionManager.h定義的各類接口的實現意外,還有處理不一樣iOS版本下NSRULSession不一樣的部分,以及多個全局dispatch_queue_t的定義、以及處理NSURLSeesionTash的各類代理方法的實現和處理。具體劃分以下:

  • NSURLSessionManager的實現。主要實現了接口文件定義的各類api的實現,好比Task的建立、Task的獲取、Task的各類代理方法的實現、NSCoping和NSCoding協議、以及各類Block的實現。

    • 基本屬性的初始化。好比sessionConfigurationoperationQueuesessionmutableTaskDelegatesKeyedByTaskIdentifier等屬性。以及用於實現task和AFURLSessionManagerTaskDelegate的綁定的taskDescriptionForSessionTasks、還有關鍵操做的鎖屬性lock。

    • 接口文件的各類Block對應的屬性,一個Block對應一個屬性。

    • 處理Task暫停與重啓操做的方法。

    • 給Task設置AFURLSessionManagerTaskDelegate代理的方法。

    • 初始化Task的各類方法。

    • 設置B接口文件定義的各類Block。

    • NSURLSession系列代理方法。

  • _AFURLSessionTaskSwizzling私有類。主要實現了iOS7和iOS8系統上NSURLSession差異的處理。讓不一樣系統版本NSURLSession版本基本一致。

  • AFURLSessionManagerTaskDelegate這個類主要是把NSURLSeesion的部分代理方法讓他處理。從而達到簡化代碼的目的。

    • 處理Task的上傳或者下載進度。

    • 處理封裝NSURLSeesion返回的數據。

    • Task完成等的通知封裝。

  • 全局dispatch_queue_tdispatch_group_t的定義。各類通知名稱的初始化,各類Block的類型定義。

3.1 AFURLSessionManager一個網絡請求實現過程

咱們經過一個網絡請求過程來分析AFURLSessionManager.m的實現。咱們經過initWithSessionConfiguration方法初始化一個manager。在這個方法裏會初始化各類屬性、以及爲session屬性設置代理:

接口文件中的代碼以下:

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

實現文件中對應的處理以下:

/**
 初始化方法
 @return 返回一個manager對象
 */
- (instancetype)init {
    return [self initWithSessionConfiguration:nil];
}
/**
 默認初始化方法、經過這個方法來作manager的具體化初始化動做

 @param configuration NSURLSession的配置
 @return 返回一個manager對象
 */
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }
    //若是用戶沒有手動指定,則使用默認的configuration來初始化
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }
    //賦值給屬性
    self.sessionConfiguration = configuration;
    //初始化NSURLSession的task代理方法執行的隊列。
    //這裏有一個很關鍵的點是task的代理執行的queque一次性只能執行一個task。這樣就避免了task的代理方法執行的混亂。
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;
    //出絲滑NSURLSession對象,最核心的對象。
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
    //若是用戶沒有手動指定,則返回的數據是JSON格式序列化。
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    //指定https處理的安全策略。
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
    //初始化網絡狀態監聽屬性
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
    //用於記錄Task與他的`AFURLSessionManagerTaskDelegate`代理對象的一一對應關係。經過這個
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    //初始化一個鎖對象,關鍵操做加鎖。
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;
    /**
     獲取當前session正在執行的全部Task。同時爲每個Task添加`AFURLSessionManagerTaskDelegate`代理對象,這個代理對象主要用於管理uplaodTak和downloadTask的進度管理。而且在Task執行完畢之後調用相應的Block。同時發送相應的notification對象,實現對task數據或者狀態改變的檢測。
     @param dataTasks dataTask列表
     @param uploadTasks uplaodTask列表
     @param downloadTasks downloadTask列表
     @return
     */
    [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];
        }
    }];
    return self;
}

請求執行,接口文件以下:

NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress *downloadProgress){
    NSLog(@"下載進度:%lld",downloadProgress.completedUnitCount);
} destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
    NSLog(@"fileURL:%@",[fileURL absoluteString]);
    return fileURL;
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:filePath]];
    NSLog(@"File downloaded to: %@", filePath);
}];

實現文件則調用了不少方法:

1 首先是初始化一個NSURLSessionDownLoadTask對象

//經過session建立一個downloadTask,
    __block NSURLSessionDownloadTask *downloadTask = nil;
    //url_session_manager_create_task_safely做用是修復在iOS8下面的系統bug。
    url_session_manager_create_task_safely(^{
        downloadTask = [self.session downloadTaskWithRequest:request];
    });
    [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
    return downloadTask;

2 經過[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];這句話來爲Task設置一個AFURLSessionManagerTaskDelegate代理對象。從而能夠實現對進度處理、Block調用、Task完成返回數據的拼裝的功能。

//根據指定的Task,初始化一個AFURLSessionManagerTaskDelegate
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
    delegate.manager = self;
    //設置Task完成的回調Block
    delegate.completionHandler = completionHandler;
    if (destination) {
        //任務完成之後,調用destination這個Block
        delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
            return destination(location, task.response);
        };
    }
    //指定Task與taskDescriptionForSessionTasks的關聯關係,方便後面的通知中作對應的處理。
    downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
    //添加通知
    [self setDelegate:delegate forTask:downloadTask];
    //設置一個下載進度的Block,以便在後面代理方法中調用。
    delegate.downloadProgressBlock = downloadProgressBlock;

3 初始化一個AFURLSessionManagerTaskDelegate對象。在這個對象中對Task的請求過程進行處理和控制。

/**
 初始化一個AFURLSessionManagerTaskDelegate對象
 @param task 對象綁定的Task
 @return 返回對象
 */
- (instancetype)initWithTask:(NSURLSessionTask *)task {
    self = [super init];
    if (!self) {
        return nil;
    }
    //這個屬性用於存儲Task下載過程當中的數據
    _mutableData = [NSMutableData data];
    //存儲Task上傳和下載的進度
    _uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
    _downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
    __weak __typeof__(task) weakTask = task;
    for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ])
    {
        progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
        progress.cancellable = YES;
        //當progress對象取消的時候,取消Task
        progress.cancellationHandler = ^{
            [weakTask cancel];
        };
        progress.pausable = YES;
        progress.pausingHandler = ^{
            //掛起Task
            [weakTask suspend];
        };
        if ([progress respondsToSelector:@selector(setResumingHandler:)]) {
            progress.resumingHandler = ^{
                //重啓Task
                [weakTask resume];
            };
        }
        //更具progress的進度來獲取Task的進度。fractionCompleted方法在請求過程當中屢次執行。
        [progress addObserver:self
                   forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                      options:NSKeyValueObservingOptionNew
                      context:NULL];
    }
    return self;
}
//上面經過對fractionCompleted方法KVO。則會調用下面的方法,從而執行manager的
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
   if ([object isEqual:self.downloadProgress]) {
       //更新下載進度Block
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }else if ([object isEqual:self.uploadProgress]) {
        //更新上傳進度Bloc
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(object);
        }
    }
}

4 在AFURLSessionManagerTaskDelegate設置Task狀態改變的監聽。

/**
 設置指定task的`AFURLSessionManagerTaskDelegate`對象。而且添加task掛起或者重啓的監聽。
 @param delegate 代理對象
 @param task task
 */
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);
    //加鎖操做
    [self.lock lock];
    //爲Task設置與之代理方法關聯關係。經過一個字典
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    //添加對Task開始、重啓、掛起狀態的通知的接收。
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}
/**
 給Task添加任務開始、重啓、掛起的通知

 @param task 任務
 */
- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}

5 從下面開始,任務就正式開始執行。其實就是[downloadTask resume];執行之後開始。

/**
 在網絡請求正式開始之後,這個方法會在數據接收的過程當中屢次調用。咱們能夠經過這個方法獲取數據下載的大小、總得大小、還有多少麼有下載
 @param session session
 @param downloadTask 對應的Task
 @param bytesWritten 已經下載的字節
 @param totalBytesWritten 總的字節大小
 @param totalBytesExpectedToWrite nil
 */
- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    //獲取Task對應的`AFURLSessionManagerTaskDelegate`對象。從而能夠調用對應的代理方法
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
    if (delegate) {
        //調用`AFURLSessionManagerTaskDelegate`類中的代理方法。從而實現對於進度更新等功能。
        //會調用下面的那個方法
        [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
    }
    if (self.downloadTaskDidWriteData) {
        //若是有`downloadTaskDidWriteData`Block的實現,則在這個調用Block從而實現對下載進度過程的控制。
        self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
    }
}
//AFURLSessionManagerTaskDelegate裏面的這個代理方法實現對進度的更新。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    //AFURLSessionManagerTaskDelegate代理方法實現對下載進度的記錄
    self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
    self.downloadProgress.completedUnitCount = totalBytesWritten;
}

6 Task完成之後,會調用AFURLSessionManagerTaskDelegate對象的方法對返回的數據封裝。

//AFURLSessionManagerTaskDelegate裏面的這個代理方法實現對數據的具體處理。
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    //獲取Task對應的manager對象
    __strong AFURLSessionManager *manager = self.manager;
    //要封裝的responseObject對象。
    __block id responseObject = nil;
    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
    //返回的數據。
    NSData *data = nil;
    if (self.mutableData) {
        data = [self.mutableData copy];
        //We no longer need the reference, so nil it out to gain back some memory.
        self.mutableData = nil;
    }
    //若是是downloadTask,則封裝downloadFileURL
    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {//若是是其餘Task,則封裝返回的data。
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }
    //有錯封裝
    if (error) {
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
        dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            //若是Task有completionHandler。則調用這個Block
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, error);
            }
            //發送一個指定Task結束的通知
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {//正確數據封裝
        //在一個並行的dispat_queuq_t對象裏面異步處理。
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            //封裝responseBojct
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
            if (self.downloadFileURL) {
                responseObject = self.downloadFileURL;
            }
            if (responseObject) {
                userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
            }
            if (serializationError) {
                userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
            }
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                //若是Task有完成Block。則調用這個Block
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                //發送通知
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }
}

7 移除Task對應的通知和對應的AFURLSessionManagerTaskDelegate代理對象。

- (void)removeDelegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);
    [self.lock lock];
    //移除Task對應的通知
    [self removeNotificationObserverForTask:task];
    //移除Task對應的`AFURLSessionManagerTaskDelegate`代理對象。
    [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
    [self.lock unlock];
}
//移除通知監聽
- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
}
//`AFURLSessionManagerTaskDelegate`對象回收。
- (void)dealloc {
    [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
    [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}

經過上面的過程,咱們發現核心流程都是圍繞了NSRULSessionTask對象以及與之綁定的AFURLSessionManagerTaskDelegate對象執行的。咱們經過在NSRULSessionTask對象的代理方法裏面手動調用AFURLSessionManagerTaskDelegate對應的代理方法來實現對數據的處理和簡化代碼的做用,這個設計思路的確吊吊的。還有一些方法沒有涉及到,不過大同小異,基本過程就是這樣,就不一一解釋了。

3.2 AFURLSessionManager一些特殊模塊的說明

AFURLSeeesionManager實現了NSSecureCoding協議。讓manager能夠歸檔解檔。

/**
 在iOS8以及以上環境下,supportsSecureCoding必須重寫而且返回true。
 @return bool
 */
+ (BOOL)supportsSecureCoding {
    return YES;
}
//解檔
- (instancetype)initWithCoder:(NSCoder *)decoder {
    NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
    self = [self initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }
    return self;
}
/**
 咱們發現對象歸檔的時候,只歸檔了`NSURLSessionConfiguration`屬性。因此說歸檔接檔的時候全部Block設置、operation設置都會失效。
 @param coder coder
 */
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
}

同時,AFURLSessionManager也實現了NSCopying協議。經過協議的實現過程,咱們發現也是隻使用了NSURLSessionConfiguration屬性。和歸檔解檔同樣。

#pragma mark - 實現NSCopying協議。copy的NAURLSessionManager沒有複製任何與代理處理相關的Block
- (instancetype)copyWithZone:(NSZone *)zone {
    return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
}

有的時候,咱們的請求會返回302這個狀態碼,這個表示須要請求重定向到另外一個url,咱們能夠下面這個代理方法裏面決定對於重定向的處理,若是對completionHandler傳入nil,則會把response傳入重定向請求。另外,backgroundSession的Task不會調用下面這個代理方法,而是直接調用。

/**
 有的時候,咱們的請求會返回302這個狀態碼,這個表示須要請求重定向到另外一個url,咱們能夠在這個代理方法裏面絕定對於重定向的處理。
 @param session session
 @param task task
 @param response response
 @param request 重定向的request。
 @param completionHandler 請求完成
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
{
    //重定向的request對象
    NSURLRequest *redirectRequest = request;
    //若是用戶指定了taskWillPerformHTTPRedirection這個Block,咱們就經過這個Block的調用返回處理完成的request對象。
    if (self.taskWillPerformHTTPRedirection) {
        redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
    }
    //這個調用是必須的,執行重定向操做。
    if (completionHandler) {
        completionHandler(redirectRequest);
    }
}

建立NSRULSessionUplaodTask的時候,在某些系統上會出現bug。AFN已經幫咱們處理好:

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    __block NSURLSessionUploadTask *uploadTask = nil;
    //用線程安全的方式建立一個dataTask。修復iOS8下面的bug。
    url_session_manager_create_task_safely(^{
        uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
    });
    //用於處理uploadTask在iOS7環境下面有可能建立失敗的狀況。若是attemptsToRecreateUploadTasksForBackgroundSessions爲true。則嘗試從新建立Task。若是三次都沒有成功,則放棄。
    if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
        for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
            uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
        }
    }
    //爲Task添加`AFURLSessionManagerTaskDelegate`代理方法
    [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
    return uploadTask;
}

經過使用dispatch_semaphore_t來控制對異步處理返回結果的控制。很是有借鑑意義。

#pragma mark -  獲取當前session對應的task列表。經過dispatch_semaphore_t來控制訪問過程。
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
    __block NSArray *tasks = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
            tasks = dataTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
            tasks = uploadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
            tasks = downloadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
            tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
        }
        //這裏發送一個信號量,讓semaphore變爲1。此時表示tasks已經成功獲取。
        dispatch_semaphore_signal(semaphore);
    }];
    //這裏會一直等待信號量變爲1。
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    //返回Task。經過信號量控制,避免了方法結束的時候,tasks尚未正常獲取的狀況。
    return tasks;
}

4 _AFURLSessionTaskSwizzling私有類的說明

在iOS7和iOS8及以上的系統,NSRULSessionTask的具體實現是不一樣的。咱們目前知道的不一樣有:

  • NSURLSessionTasks是一個類簇。因此咱們初始化一個Task的時候,咱們並不僅到初始化的究竟是哪一個子類。

  • 簡單的經過[NSURLSessionTask class]並不會起做用。必須經過NSURLSession建立一個task對象。而後獲取他所在的類。

  • iOS7下面,下面代碼中的localDataTask對象的繼承關係是__NSCFLocalDataTask -> __NSCFLocalSessionTask -> __NSCFURLSessionTask

  • 在iOS8以及以上系統。下面代碼中的localDataTask對象的繼承關係是__NSCFLocalDataTask -> __NSCFLocalSessionTask -> NSURLSessionTask

  • 在iOS7下面__NSCFLocalSessionTask__NSCFURLSessionTask實現了resumesuspend方法,同時最重要的是他不調用父類的實現。可是iOS8下面,只有NSURLSessionTask實現了resumesuspend。因此在iOS7的環境下,咱們須要想辦法讓resumesuspend調用NSURLSessionTask的具體實現。

下面的代碼完美的向咱們展現了一個向類添加方法,而且swizzle方法實現的過程。值得仔細琢磨。

/**
 切換theClass類的`originalSelector`和`swizzledSelector`的實現
 @param theClass 類
 @param originalSelector 方法一
 @param swizzledSelector 方法2
 */
static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
    Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}
/**
 動態給一個類添加方法
 @param theClass 類
 @param selector 方法名字
 @param method 方法體
 @return bool
 */
static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
    return class_addMethod(theClass, selector,  method_getImplementation(method),  method_getTypeEncoding(method));
}
@implementation _AFURLSessionTaskSwizzling
+ (void)load {
    if (NSClassFromString(@"NSURLSessionTask")) {
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
        NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
        //初始化一個dataTask對象
        NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
#pragma clang diagnostic pop
        //獲取af_resume這個方法的實現。
        IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
        //獲取dataTask的具體類
        Class currentClass = [localDataTask class];
        //若是父類有resume方法。則改變方法的具體實現。
        while (class_getInstanceMethod(currentClass, @selector(resume))) {
            Class superClass = [currentClass superclass];
            //找到類和父類的resume方法實現
            IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
            IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
            if (classResumeIMP != superclassResumeIMP &&
                originalAFResumeIMP != classResumeIMP) {
                //添加方法、而後轉換方法的實現
                [self swizzleResumeAndSuspendMethodForClass:currentClass];
            }
            currentClass = [currentClass superclass];
        }
        [localDataTask cancel];
        [session finishTasksAndInvalidate];
    }
}
/**
 主要是實現了爲一個類添加方法、而且轉換添加方法和原來對應方法的實現。
 @param theClass 要操做的類
 */
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
    Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
    Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
    //爲theClass類添加一個af_resume方法。
    if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
        //把dataTask的resume和afresume方法的實現互換。
        af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
    }
    //爲theClass類添加一個af_suspend方法
    if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
        //把dataTask的suspend和af_suspend方法的實現互換。
        af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
    }
}
- (NSURLSessionTaskState)state {
    NSAssert(NO, @"State method should never be called in the actual dummy class");
    return NSURLSessionTaskStateCanceling;
}
/**
 在iOS7下面,`NSURLSessionDataTask`調用resume方法其實就是執行`af_resume`的具體實現。
 */
- (void)af_resume {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    //這裏其實就是調用dataTask的resume實現
    [self af_resume];
    if (state != NSURLSessionTaskStateRunning) {
        //這裏的self其實就是`NSRULSessionDataTask`對象
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
    }
}
/**
 在iOS7下面,`NSURLSessionDataTask`調用suspend方法其實就是執行`af_suspend`的具體實現。
 */
- (void)af_suspend {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    //這裏其實就是調用dataTask的suspend具體實現
    [self af_suspend];
    if (state != NSURLSessionTaskStateSuspended) {
        //這裏的self其實就是`NSRULSessionDataTask`對象
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
    }
}
@end

5 總結

AFURLSessionManager經過對task設置一個AFURLSessionManagerTaskDelegate代理來處理繁雜的請求進度管理。從而下降了代碼的負責度。是代理模式的一個很好的實踐。

AFURLSessionManager經過私有類_AFURLSessionTaskSwizzling來修改iOS7和iOS8系統上面不一樣。是對於方法swizzle的一個成功和完整的實踐。

AFURLSessionManager經過添加各類Block,讓咱們對請求過程有全方位的控制和處理。同時提供簡潔的api,把負責的處理所有封裝好。

源碼地址iOSSourceCodeStudy,博客地址博客地址

相關文章
相關標籤/搜索