iOS網(wǎng)絡(luò)——AFNetworking AFURLSessionManager源碼解析

你要知道的NSURLSession都在這里

轉(zhuǎn)載請注明出處 http://www.reibang.com/p/167e7e2cbc9e

本系列文章主要講解iOS中網(wǎng)絡(luò)請求類NSURLSession的使用方法進(jìn)行詳解虎锚,同時(shí)也會以此為擴(kuò)展谤职,講解SDWebImage中圖片下載功能的源碼分析吮成,講解AFNetworking相關(guān)源碼分析。本系列文章主要分為以下幾篇進(jìn)行講解偿枕,讀者可按需查閱徙硅。

AFNetworking AFURLSessionManager源碼解析

前面幾篇文章講解了NSURLSession的基礎(chǔ)使用方法以及SDWebImage在下載圖片時(shí)是如何使用NSURLSession,來完成下載任務(wù)的唉俗,本篇文章將閱讀AFNetworking是如何封裝NSURLSession來提供便捷的網(wǎng)絡(luò)請求功能。

AFNetworking的使用方法就不贅述了配椭,我們經(jīng)常使用AFHttpSessionManager來發(fā)起一個(gè)GET或是POST請求虫溜,該類是繼承自AFURLSessionManager并在其上進(jìn)行了一個(gè)封裝,提供了更加便捷的接口來發(fā)起網(wǎng)絡(luò)請求股缸,所以本篇將詳細(xì)講解AFURLSessionManager是如何封裝NSURLSession的衡楞,建議讀者對照源碼閱讀。

首先看一下頭文件的聲明:

//AFURLSessionManager類實(shí)現(xiàn)了NSURLSession相關(guān)的眾多協(xié)議敦姻,用于幫助我們進(jìn)行數(shù)據(jù)的處理
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>

//豬腳瘾境,NSURLSession 作為一個(gè)實(shí)例變量,AFN發(fā)起的網(wǎng)絡(luò)請求都是通過該session創(chuàng)建的task實(shí)現(xiàn)的
@property (readonly, nonatomic, strong) NSURLSession *session;

//NSURLSession delegate方法執(zhí)行隊(duì)列
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

//響應(yīng)序列化镰惦,不是本系列文章的關(guān)注點(diǎn)寄雀,有興趣的讀者可以自行閱讀源碼
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;

///-------------------------------
/// @name Managing Security Policy
///-------------------------------
//安全策略,用于https等需要驗(yàn)證的地方
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

#if !TARGET_OS_WATCH
///--------------------------------------
/// @name Monitoring Network Reachability
///--------------------------------------

//監(jiān)測網(wǎng)絡(luò)連通性陨献,使用AFNetworkReachabilityManager盒犹,讀者可自行閱讀相關(guān)源碼
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
#endif

///----------------------------
/// @name Getting Session Tasks
///----------------------------

//前面那個(gè)session管理的data upload download task的集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;

//前面那個(gè)session管理的data task的集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;

//前面那個(gè)session管理的upload task的集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;

//前面那個(gè)session管理的download task的集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

///-------------------------------
/// @name Managing Callback Queues
///-------------------------------

//完成網(wǎng)絡(luò)請求后執(zhí)行回調(diào)塊的隊(duì)列,如果為nil則使用主隊(duì)列
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;

//完成網(wǎng)絡(luò)請求后回調(diào)塊的
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

///---------------------------------
/// @name Working Around System Bugs
///---------------------------------

//background類型的session是否嘗試重新創(chuàng)建上傳任務(wù)
@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;

///---------------------
/// @name Initialization
///---------------------

//初始化函數(shù)眨业,根據(jù)指定NSURLSessionConfiguration創(chuàng)建session
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

//設(shè)置session無效急膀,cancelPendingTasks標(biāo)識是否取消session中正在執(zhí)行的任務(wù)
//內(nèi)部還是調(diào)用NSURLSession的invalidate方法
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;

///-------------------------
/// @name Running Data Tasks
///-------------------------

//根據(jù)指定的request等信息創(chuàng)建一個(gè)NSURLSessionDataTask任務(wù)
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;

//根據(jù)指定的request等參數(shù)創(chuàng)建一個(gè)NSURLSessionDataTask任務(wù)
- (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;

///---------------------------
/// @name Running Upload Tasks
///---------------------------

//根據(jù)指定request fileURL等參數(shù)構(gòu)造一個(gè)NSURLSessionUploadTask任務(wù)
- (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;

//根據(jù)指定request和data等參數(shù)構(gòu)造一個(gè)上傳任務(wù)
- (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;

//根據(jù)指定的request構(gòu)造一個(gè)上傳任務(wù)
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

///-----------------------------
/// @name Running Download Tasks
///-----------------------------

//構(gòu)造下載任務(wù)
- (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;

//構(gòu)造下載任務(wù)
- (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;

///---------------------------------
/// @name Getting Progress for Tasks
///---------------------------------

//根據(jù)NSURLSessionTask獲取對應(yīng)的任務(wù)完成進(jìn)度NSProgress
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;

//根據(jù)NSURLSessionTask獲取對應(yīng)下載任務(wù)的進(jìn)度NSProgress
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;

///-----------------------------------------
/// @name Setting Session Delegate Callbacks
///-----------------------------------------
//設(shè)置session無效時(shí)執(zhí)行的回調(diào)塊
- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;

//設(shè)置session收到challenge時(shí)執(zhí)行的回調(diào)塊
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

///--------------------------------------
/// @name Setting Task Delegate Callbacks
///--------------------------------------

//設(shè)置session需要新的流時(shí)執(zhí)行的回調(diào)塊
- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;

//設(shè)置session的任務(wù)需要執(zhí)行重定向時(shí)執(zhí)行的回調(diào)塊
- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * _Nullable (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;

//又是代理方法執(zhí)行時(shí)需要執(zhí)行的回調(diào)塊
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

//同上
- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;

//同上
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;

///-------------------------------------------
/// @name Setting Data Task Delegate Callbacks
///-------------------------------------------

/**
 Sets a block to be executed when a data task has received a response, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didReceiveResponse:completionHandler:`.

 @param block A block object to be executed when a data task has received a response. The block returns the disposition of the session response, and takes three arguments: the session, the data task, and the received response.
 */
- (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block;

//同上
- (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block;

//同上
- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;

//同上
- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;

//同上
- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block;

///-----------------------------------------------
/// @name Setting Download Task Delegate Callbacks
///-----------------------------------------------
//同上
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable  (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;

//同上
- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;

//同上
- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;

@end

///--------------------
/// @name Notifications
///--------------------

//一些通知的名稱,使用FOUNDATION_EXPORT標(biāo)識

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidResumeNotification;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteNotification;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidSuspendNotification;

FOUNDATION_EXPORT NSString * const AFURLSessionDidInvalidateNotification;

FOUNDATION_EXPORT NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseDataKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteAssetPathKey;

FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteErrorKey;

NS_ASSUME_NONNULL_END

通過頭文件可以發(fā)現(xiàn)龄捡,AFURLSessionManager是封裝了NSURLSession并實(shí)現(xiàn)了其相關(guān)的所有協(xié)議卓嫂,提供了一系列方法用于構(gòu)造各種網(wǎng)絡(luò)請求任務(wù),并提供回調(diào)塊進(jìn)行處理聘殖,還提供了一系列設(shè)置代理方法執(zhí)行時(shí)的執(zhí)行回調(diào)塊的方法晨雳,這樣,我們也可以監(jiān)聽整個(gè)網(wǎng)絡(luò)請求的過程奸腺,當(dāng)然也可以忽略這些代理方法執(zhí)行情況餐禁,提供了各種通知,通過頭文件可以看出突照,主要目的還是為了封裝NSURLSession從而提供更加便捷的方法來實(shí)現(xiàn)網(wǎng)絡(luò)請求帮非。

接下來看一下實(shí)現(xiàn)的文件:

//C靜態(tài)函數(shù),GCD只執(zhí)行一次,用于創(chuàng)建一個(gè)串行隊(duì)列來執(zhí)行各種網(wǎng)絡(luò)請求任務(wù)的創(chuàng)建工作
static dispatch_queue_t url_session_manager_creation_queue() {
    static dispatch_queue_t af_url_session_manager_creation_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL);
    });

    return af_url_session_manager_creation_queue;
}

/*
C靜態(tài)函數(shù)末盔,用于執(zhí)行創(chuàng)建網(wǎng)絡(luò)請求任務(wù)的block
主要目的是為了解決ios8以下存在的一個(gè)block和task不匹配的bug
上面那個(gè)隊(duì)列也是為了解決這個(gè)bug才創(chuàng)建的
具體可查看
Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
*/
static void url_session_manager_create_task_safely(dispatch_block_t block) {
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
        dispatch_sync(url_session_manager_creation_queue(), block);
    } else {
        block();
    }
}

//C靜態(tài)函數(shù)筑舅,創(chuàng)建一個(gè)并發(fā)隊(duì)列,用于在網(wǎng)絡(luò)請求任務(wù)完成后處理數(shù)據(jù)的陨舱,并發(fā)隊(duì)列實(shí)現(xiàn)多線程處理多個(gè)請求完成后的數(shù)據(jù)處理
static dispatch_queue_t url_session_manager_processing_queue() {
    static dispatch_queue_t af_url_session_manager_processing_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT);
    });

    return af_url_session_manager_processing_queue;
}
//C靜態(tài)函數(shù)創(chuàng)建一個(gè)dispatch的組
//但在接下來的源碼中并沒有使用這個(gè)組來實(shí)現(xiàn)notify等功能翠拣,僅僅是將block和組關(guān)聯(lián)了,不太清楚具體用意
//有明白的讀者還請不吝賜教
static dispatch_group_t url_session_manager_completion_group() {
    static dispatch_group_t af_url_session_manager_completion_group;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        af_url_session_manager_completion_group = dispatch_group_create();
    });

    return af_url_session_manager_completion_group;
}
//一系列通知名稱的定義
NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume";
NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete";
NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend";
NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";
NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";

NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";
NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";
NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";
NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";
NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";

//需要使用的NSLock鎖的名稱
static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";

//background session重試創(chuàng)建上傳任務(wù)次數(shù)
static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;

上面的代碼定義了一系列GCD隊(duì)列游盲,根據(jù)需求有串行隊(duì)列和并行隊(duì)列误墓,串行隊(duì)列可以解決多線程情況下競爭條件的產(chǎn)生,并發(fā)隊(duì)列可以提高性能背桐,每個(gè)隊(duì)列都有自己的功能优烧,接下來會講到,接下來定義了各種通知的名稱链峭。

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);

上面是一系列回調(diào)塊的定義畦娄,在閱讀下面源碼的時(shí)候可以來找找看具體回調(diào)塊的參數(shù)。

//定義了一個(gè)類AFURLSessionManagerTaskDelegate并實(shí)現(xiàn)了NSURLSessionTask的相關(guān)協(xié)議
//通過名稱可以猜測弊仪,這個(gè)類是用于處理NSURLSessionTask相關(guān)代理方法的
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>

//初始化構(gòu)造函數(shù)熙卡,需要傳入一個(gè)關(guān)聯(lián)的task
- (instancetype)initWithTask:(NSURLSessionTask *)task;

//weak修飾的manager
@property (nonatomic, weak) AFURLSessionManager *manager;
//可變data用于存儲獲取到的網(wǎng)絡(luò)數(shù)據(jù)
@property (nonatomic, strong) NSMutableData *mutableData;
//上傳進(jìn)度NSProgress
@property (nonatomic, strong) NSProgress *uploadProgress;
//下載進(jìn)度NSProgress
@property (nonatomic, strong) NSProgress *downloadProgress;
//下載文件的NSURL
@property (nonatomic, copy) NSURL *downloadFileURL;
//下載完成的回調(diào)塊
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
//上傳進(jìn)度的回調(diào)塊
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
//下載進(jìn)度的回調(diào)塊
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
//網(wǎng)絡(luò)請求完成的回調(diào)塊
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
@end

@implementation AFURLSessionManagerTaskDelegate

//初始化構(gòu)造函數(shù)
- (instancetype)initWithTask:(NSURLSessionTask *)task {
    self = [super init];
    if (!self) {
        return nil;
    }
    
    _mutableData = [NSMutableData data];
    _uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
    _downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
    
    //遍歷兩個(gè)上傳和下載NSProgress設(shè)置一些屬性
    __weak __typeof__(task) weakTask = task;
    for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ])
    {
        //初始化progress
        progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
        progress.cancellable = YES;
        //設(shè)置取消進(jìn)度的回調(diào)塊,執(zhí)行task的cancel方法
        progress.cancellationHandler = ^{
            [weakTask cancel];
        };
        progress.pausable = YES;
        //設(shè)置暫停進(jìn)度的回調(diào)塊励饵,執(zhí)行task的suspend方法
        progress.pausingHandler = ^{
            [weakTask suspend];
        };
        //設(shè)置重新開始的回調(diào)塊驳癌,執(zhí)行task的resume方法
        if ([progress respondsToSelector:@selector(setResumingHandler:)]) {
            progress.resumingHandler = ^{
                [weakTask resume];
            };
        }
        //progress添加kvo,監(jiān)聽progress的進(jìn)度fractionCompleted
        [progress addObserver:self
                   forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                      options:NSKeyValueObservingOptionNew
                      context:NULL]; 
    }
    return self;
}

//析構(gòu)函數(shù)
- (void)dealloc {
    //刪除KVO
    [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
    [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}

#pragma mark - NSProgress Tracking
//KVO回調(diào)方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    //上次或下載進(jìn)度有改變時(shí)役听,執(zhí)行上傳或下載進(jìn)度回調(diào)塊
   if ([object isEqual:self.downloadProgress]) {
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }
    else if ([object isEqual:self.uploadProgress]) {
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(object);
        }
    }
}

#pragma mark - NSURLSessionTaskDelegate
//代理方法颓鲜,網(wǎng)絡(luò)請求完成或出錯(cuò)
- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    //manager用weak修飾,這里strong一下防止manager被釋放
    __strong AFURLSessionManager *manager = self.manager;

    __block id responseObject = nil;

    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    //為userInfo字典設(shè)置響應(yīng)序列化
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;

    //Performance Improvement from #2672
    //賦值mutableData到data中典予,并釋放mutableData
    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;
    }
    //如果downloadFileURL存在甜滨,即是下載任務(wù)就設(shè)置下載完成后的文件存儲url到字典中
    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
    //否則就設(shè)置對應(yīng)的NSData數(shù)據(jù)到字典中
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }
    //如果網(wǎng)絡(luò)請求有錯(cuò)誤
    if (error) {
        //設(shè)置error信息到字典中
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
        /*
        這個(gè)三目運(yùn)算符需要解釋一下,在其他語言中這么寫很可能就是語法錯(cuò)誤
        這里的意思就是如果manager.completionGroup存在就使用它
        不存在就使用url_session_manager_completion_group函數(shù)返回的group
        后面的三目運(yùn)算符同理
        所以如果自己不設(shè)置manager的completionGroup或completionQueue就會使用默認(rèn)提供的
        */
        //執(zhí)行對應(yīng)的completionHandler回調(diào)塊
        dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, error);
            }
            //在主隊(duì)列即主線程中發(fā)送通知
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {
        //如果網(wǎng)絡(luò)任務(wù)成功完成瘤袖,異步在并發(fā)隊(duì)列中執(zhí)行數(shù)據(jù)處理
        dispatch_async(url_session_manager_processing_queue(), ^{
            //序列化響應(yīng)數(shù)據(jù)
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
            //如果是下載任務(wù)設(shè)置響應(yīng)數(shù)據(jù)為文件的url
            if (self.downloadFileURL) {
                responseObject = self.downloadFileURL;
            }
            //如果響應(yīng)對象序列化成功或是文件url就設(shè)置相關(guān)字典key-value
            if (responseObject) {
                userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
            }
            //如果序列化出錯(cuò)衣摩,設(shè)置相關(guān)字典值
            if (serializationError) {
                userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
            }
            //同理,在dispatch組中和特定隊(duì)列執(zhí)行回調(diào)塊
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                //主線程發(fā)送通知
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }
}

#pragma mark - NSURLSessionDataDelegate
//回調(diào)方法捂敌,收到數(shù)據(jù)
- (void)URLSession:(__unused NSURLSession *)session
          dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    //設(shè)置下載進(jìn)度的相關(guān)屬性
    self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
    self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;
    //添加數(shù)據(jù)到mutableData
    [self.mutableData appendData:data];
}

//上傳任務(wù)的回調(diào)方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
    //設(shè)置上傳進(jìn)度的相關(guān)屬性
    self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    self.uploadProgress.completedUnitCount = task.countOfBytesSent;
}

#pragma mark - NSURLSessionDownloadDelegate

//下載任務(wù)的回調(diào)方法
//由于NSURLSession的downloadTask直接將文件下載到磁盤沙盒中艾扮,所以不需要mutableData自行接收數(shù)據(jù)
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    //設(shè)置下載進(jìn)度的相關(guān)屬性
    self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
    self.downloadProgress.completedUnitCount = totalBytesWritten;
}

//恢復(fù)下載任務(wù)的回調(diào)方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
    //設(shè)置下載進(jìn)度的相關(guān)屬性
    self.downloadProgress.totalUnitCount = expectedTotalBytes;
    self.downloadProgress.completedUnitCount = fileOffset;
}

//下載任務(wù)下載文件完成后的回調(diào)方法
//location就是文件下載到磁盤沙盒目錄的NSURL
- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    //設(shè)置downloadFileURL為nil
    self.downloadFileURL = nil;
    //如果有下載完成的回調(diào)塊
    if (self.downloadTaskDidFinishDownloading) {
        //執(zhí)行該回調(diào)塊,這個(gè)回調(diào)塊返回一個(gè)下載的文件保存的路徑URL
        //默認(rèn)保存在沙盒tmp文件中占婉,可能會被刪除泡嘴,需要持久化時(shí)要自己設(shè)置一個(gè)目錄存儲
        self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
        //如果需要移動文件的路徑使用NSFileManaegr移動
        if (self.downloadFileURL) {
            NSError *fileManagerError = nil;

            if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
                //文件移動發(fā)生錯(cuò)誤發(fā)送通知
                [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
            }
        }
    }
}

@end

上面這個(gè)類AFURLSessionManagerTaskDelegate具體的源碼很簡單,主要就是關(guān)聯(lián)一個(gè)NSURLSessionTask并實(shí)現(xiàn)了相關(guān)任務(wù)的代理方法用于數(shù)據(jù)的獲取锐涯、上傳文件和下載文件磕诊。需要注意的是NSURLSessionTaskdelegate屬性是只讀的呜师,只能在使用session創(chuàng)建task的函數(shù)中傳入代理對象胯盯,而且通過源碼也沒有發(fā)現(xiàn)相關(guān)代理的設(shè)置补憾,所以AFURLSessionManagerTaskDelegate類實(shí)現(xiàn)相關(guān)代理是為了其他類手動調(diào)用相關(guān)方法背犯,AFURLSessionManager也實(shí)現(xiàn)了這些代理翁垂,所以具體的調(diào)用是由AFURLSessionManger手動觸發(fā)的膏秫。

接下來的源碼中有一部分關(guān)于method-swizzling的技術(shù)提佣,這一部分由于篇幅問題不打算展開講解荒叼,_AFURLSessionTaskSwizzling類存在的目的就是為了交換NSURLSessionTaskresumesuspend方法的實(shí)現(xiàn)涎劈,因?yàn)?code>iOS7和iOS8NSURLSessionTask的父類不同广凸,需要做一些處理,關(guān)于method-swizzling技術(shù)有興趣的讀者可以閱讀iOS runtime探究(四): 從runtiem開始實(shí)踐Category添加屬性與黑魔法method swizzling

接下來看一下AFURLSessionManager類的實(shí)現(xiàn)部分蛛枚。

@interface AFURLSessionManager ()
//管理的session運(yùn)行模式谅海,默認(rèn)情況下使用默認(rèn)運(yùn)行模式,defaultConfiguration
@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
/*
NSOperation隊(duì)列蹦浦,代理方法執(zhí)行的隊(duì)列
.h文件里是readonly扭吁,所以這里定義一個(gè)readwrite用于賦值
*/
@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
//管理的session,readwrite
@property (readwrite, nonatomic, strong) NSURLSession *session;
//可變字典盲镶,key是NSURLSessionTask的唯一NSUInteger類型標(biāo)識侥袜,value是對應(yīng)的AFURLSessionManagerTaskDelgate對象
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
//只讀屬性,通過getter返回?cái)?shù)據(jù)
@property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
//NSLock鎖
@property (readwrite, nonatomic, strong) NSLock *lock;
//下面是一系列回調(diào)塊
@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;
@end

上面就是定義了一系列的回調(diào)塊和一些屬性溉贿。

@implementation AFURLSessionManager
//構(gòu)造函數(shù)
- (instancetype)init {
    return [self initWithSessionConfiguration:nil];
}
//構(gòu)造函數(shù)
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }
    //如果沒有指定session運(yùn)行模式就使用默認(rèn)的
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    self.sessionConfiguration = configuration;
    //創(chuàng)建代理方法執(zhí)行的隊(duì)列枫吧,最大并發(fā)數(shù)為1,即串行隊(duì)列
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;
    //創(chuàng)建session宇色,注意代理對象是self
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
    //創(chuàng)建響應(yīng)序列化器
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    //設(shè)置默認(rèn)安全策略
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    //獲取網(wǎng)絡(luò)可達(dá)性manager
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif

    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    //創(chuàng)建鎖
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;
    /*
    獲取session中的任務(wù)九杂,并調(diào)用相關(guān)方法關(guān)聯(lián)AFURLSessionManagerTaskDelegate
    不太明白這里為什么要這么做,剛創(chuàng)建的session應(yīng)該沒有任何任務(wù)在執(zhí)行
    */
    [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;
}

//析構(gòu)方法宣蠕,移除所有通知監(jiān)聽
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

初始化方法中不太理解的地方就是在創(chuàng)建完session后就去獲取它正在執(zhí)行的相關(guān)任務(wù)例隆,但是剛創(chuàng)建的session為什么會存在正在執(zhí)行的任務(wù)呢?如果有讀者明白還請不吝賜教植影。

//taskDescriptionForSessionTasks屬性的getter裳擎,返回地址的字符串形式數(shù)據(jù),可以保證這個(gè)字符串是唯一的
- (NSString *)taskDescriptionForSessionTasks {
    return [NSString stringWithFormat:@"%p", self];
}
//通知的回調(diào)方法思币,接下來的代碼會添加相關(guān)通知
- (void)taskDidResume:(NSNotification *)notification {
    //發(fā)送通知的時(shí)候會將task添加進(jìn)通知中
    NSURLSessionTask *task = notification.object;
    //判斷這個(gè)任務(wù)是否是當(dāng)前manager管理的鹿响,如果是就發(fā)送相關(guān)通知
    //task的taskDescription屬性在下文的源碼中會設(shè)置
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
            });
        }
    }
}
//同上
- (void)taskDidSuspend:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
            });
        }
    }
}

上面的代碼就是通知的回調(diào)方法,用于通知resume和suspend事件谷饿。

//根據(jù)task獲取相關(guān)聯(lián)的AFURLSessionManagerTaskDelegate對象
- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
    //task不能為空
    NSParameterAssert(task);
    //上鎖惶我,通過task的唯一taskIdentifier從字典中取值,這個(gè)唯一標(biāo)識是在創(chuàng)建task的時(shí)候NSURLSessionTask為其設(shè)置的博投,不需要手動設(shè)置绸贡,保證唯一性
    AFURLSessionManagerTaskDelegate *delegate = nil;
    [self.lock lock];
    delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
    [self.lock unlock];

    return delegate;
}
//為task設(shè)置關(guān)聯(lián)的delegate
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    //task和delegate都不能為空
    NSParameterAssert(task);
    NSParameterAssert(delegate);
    //上鎖,向字典中添加key-value對
    [self.lock lock];
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

//重點(diǎn)方法,為dataTask創(chuàng)建一個(gè)關(guān)聯(lián)的AFURLSessionManagerTaskDelegate對象
- (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] initWithTask:dataTask];
    //設(shè)置相關(guān)屬性
    delegate.manager = self;
    delegate.completionHandler = completionHandler;
    /*
    設(shè)置task的taskDescription听怕,注意和taskIdentifier區(qū)分
    taskDescription是開發(fā)者自行設(shè)置的
    taskIdentifier是NSURLSessionTask設(shè)置的捧挺,保證每一個(gè)task的id不同
    這里設(shè)置的taskDescription就是AFURLSessionManager的地址
    所以同一個(gè)manager創(chuàng)建的task的description都是一致的
    設(shè)置這個(gè)值的目的就是為了區(qū)分task是否是當(dāng)前manger創(chuàng)建的
    */
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    //調(diào)用上面的方法將task-delegate鍵值對添加進(jìn)字典中
    [self setDelegate:delegate forTask:dataTask];
    //設(shè)置回調(diào)塊
    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

//同上,創(chuàng)建上傳任務(wù)的AFURLSessionManagerTaskDelegate對象尿瞭,并加入到字典中
- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
                        progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
               completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    uploadTask.taskDescription = self.taskDescriptionForSessionTasks;

    [self setDelegate:delegate forTask:uploadTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
}

//同上闽烙,創(chuàng)建下載文件任務(wù)的AFURLSessionManagerTaskDelegate對象,并加入到字典中
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
                          progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                       destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                 completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    /*
    需要注意下声搁,AFURLSessionManagerTaskDelegate中下載文件完成后會調(diào)用delegate.downloadTaskDidFinishDownloading回調(diào)塊
    來獲取下載文件要移動到的目錄URL
    所以這里就是創(chuàng)建這個(gè)回調(diào)塊黑竞,直接返回參數(shù)中的destination回調(diào)塊
    */
    if (destination) {
        delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
            return destination(location, task.response);
        };
    }

    downloadTask.taskDescription = self.taskDescriptionForSessionTasks;

    [self setDelegate:delegate forTask:downloadTask];

    delegate.downloadProgressBlock = downloadProgressBlock;
}
//從字典中刪除task對應(yīng)的delegate的key-value對
- (void)removeDelegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    [self.lock lock];
    [self removeNotificationObserverForTask:task];
    [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
    [self.lock unlock];
}

上面的代碼就是對AFURLSessionManagerTaskDelegate的創(chuàng)建、添加進(jìn)字典疏旨、刪除很魂、獲取的操作,這樣就實(shí)現(xiàn)了每一個(gè)NSURLSessionTask對應(yīng)一個(gè)AFURLSessionManagerTaskDelegate對象檐涝,可能讀者會有疑問遏匆,AFURLSessionManager既然已經(jīng)實(shí)現(xiàn)了代理的方法,為什么不直接使用它來處理代理方法骤铃,為什么要?jiǎng)?chuàng)建一個(gè)類來專門處理拉岁,繼續(xù)看完源碼可能你就會明白了。

//根據(jù)keyPath獲取不同類型任務(wù)的集合
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
    __block NSArray *tasks = nil;
    //創(chuàng)建一個(gè)信號量惰爬,值是0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    //這個(gè)方法是異步的喊暖,所以為了同步返回結(jié)果,需要使用鎖撕瞧,信號量值設(shè)置為0或者1時(shí)就可以當(dāng)鎖來使用了
    [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"];
        }
        //signal通知信號量陵叽,信號量值加1
        dispatch_semaphore_signal(semaphore);
    }];
    //等待信號量,直到值大于0丛版,等待時(shí)間是forever
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    return tasks;
}
//下面是tasks巩掺、dataTasks、uploadTasks页畦、downloadTasks屬性的getter胖替,都是調(diào)用上述方法來獲取對應(yīng)類型的任務(wù)集合
- (NSArray *)tasks {
    return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
}

- (NSArray *)dataTasks {
    return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
}

- (NSArray *)uploadTasks {
    return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
}

- (NSArray *)downloadTasks {
    return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
}

#pragma mark -
//設(shè)置session無效,根據(jù)參數(shù)判斷是否需要取消正在執(zhí)行的任務(wù)
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {  
    //調(diào)用NSURLSession對應(yīng)的方法來設(shè)置session無效豫缨,同時(shí)打破引用循環(huán)
    if (cancelPendingTasks) {
        [self.session invalidateAndCancel];
    } else {
        [self.session finishTasksAndInvalidate];
    }
}

#pragma mark -
//responseSerializer的setter
- (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerializer {
    NSParameterAssert(responseSerializer);

    _responseSerializer = responseSerializer;
}

#pragma mark -
//添加通知独令,taskDidResume、taskDidSuspend方法前面講過了
- (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];
}
//刪除通知
- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
}

上面的方法是一些getter和setter好芭,很簡單燃箭,不再贅述。

//創(chuàng)建并返回NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
}

//創(chuàng)建并返回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 {
    
    //為了解決iOS8一下的一個(gè)bug舍败,調(diào)用一個(gè)串行隊(duì)列來創(chuàng)建dataTask
    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
        //使用session來創(chuàng)建一個(gè)NSURLSessionDataTask對象
        dataTask = [self.session dataTaskWithRequest:request];
    });
    //為這個(gè)task創(chuàng)建一個(gè)AFURLSessionManagerTaskDelegate并關(guān)聯(lián)加入字典中
    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

#pragma mark -
//創(chuàng)建一個(gè)NSURLSessionUploadTask對象
- (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;
    url_session_manager_create_task_safely(^{
        uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
    });

    // uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113)
    //解決iOS7的一個(gè)bug按照配置的嘗試次數(shù)創(chuàng)建上傳任務(wù)招狸,默認(rèn)嘗試3次
    if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
        for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
            uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
        }
    }
    //創(chuàng)建關(guān)聯(lián)的delegate并添加到字典中
    [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];

    return uploadTask;
}
//同上
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(NSData *)bodyData
                                         progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                                completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    __block NSURLSessionUploadTask *uploadTask = nil;
    url_session_manager_create_task_safely(^{
        uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
    });

    [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];

    return uploadTask;
}
//同上
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                                        completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    __block NSURLSessionUploadTask *uploadTask = nil;
    url_session_manager_create_task_safely(^{
        uploadTask = [self.session uploadTaskWithStreamedRequest:request];
    });

    [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];

    return uploadTask;
}

#pragma mark -
//創(chuàng)建下載任務(wù)敬拓,同上
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                                          destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
    __block NSURLSessionDownloadTask *downloadTask = nil;
    url_session_manager_create_task_safely(^{
        downloadTask = [self.session downloadTaskWithRequest:request];
    });

    [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];

    return downloadTask;
}
//創(chuàng)建下載任務(wù),同上
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                                             destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                       completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
    __block NSURLSessionDownloadTask *downloadTask = nil;
    url_session_manager_create_task_safely(^{
        downloadTask = [self.session downloadTaskWithResumeData:resumeData];
    });

    [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];

    return downloadTask;
}

上面的方法就是AFURLSessionManager為我們提供的獲取NSURLSessionDataTask裙戏、NSURLSessionUploadTaskNSURLSessionDownloadTask的方法乘凸,上面這些方法主要目的就是傳入進(jìn)度或完成回調(diào)塊,然后構(gòu)造一個(gè)AFURLSessionManagerTaskDeleagte對象并關(guān)聯(lián)挽懦,這樣就不需要開發(fā)者自行實(shí)現(xiàn)和管理代理方法做相關(guān)數(shù)據(jù)處理翰意,只需要在回調(diào)塊中做處理即可木人。

接下來源碼中是一系列回調(diào)塊的setter方法信柿,就不列下來了,讀者可以自己看看醒第。接下來就講解重點(diǎn)的各種代理的回調(diào)方法渔嚷。

//session無效后的回調(diào)方法
- (void)URLSession:(NSURLSession *)session
didBecomeInvalidWithError:(NSError *)error
{
    //如果回調(diào)塊存在就執(zhí)行回調(diào)塊
    if (self.sessionDidBecomeInvalid) {
        self.sessionDidBecomeInvalid(session, error);
    }
    //發(fā)送對應(yīng)通知
    [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}

//收到服務(wù)端的challenge,例如https需要驗(yàn)證證書等
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;
    
    //如果有對應(yīng)回調(diào)塊就執(zhí)行
    if (self.sessionDidReceiveAuthenticationChallenge) {
        disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
    } else {
        //處理https
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                if (credential) {
                    disposition = NSURLSessionAuthChallengeUseCredential;
                } else {
                    disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                }
            } else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

上面兩個(gè)方法是NSURLSessionDelegate的方法稠曼,關(guān)于驗(yàn)證HTTPS的部分代碼可以當(dāng)做模板代碼來寫形病,具體內(nèi)容不是本文講解范疇,讀者可自行查閱霞幅。

//要執(zhí)行重定向的代理方法
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest *))completionHandler
{
    //套路就是執(zhí)行用戶自定義的回調(diào)塊漠吻,執(zhí)行完成回調(diào)塊
    NSURLRequest *redirectRequest = request;

    if (self.taskWillPerformHTTPRedirection) {
        redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
    }

    if (completionHandler) {
        completionHandler(redirectRequest);
    }
}

//同前面一樣,處理https鏈接
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;

    if (self.taskDidReceiveAuthenticationChallenge) {
        disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
    } else {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                disposition = NSURLSessionAuthChallengeUseCredential;
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            } else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}
//處理需要一個(gè)新的流
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
{
    //調(diào)用用戶自定義的回調(diào)塊來獲取司恳,或者copy一個(gè)
    NSInputStream *inputStream = nil;

    if (self.taskNeedNewBodyStream) {
        inputStream = self.taskNeedNewBodyStream(session, task);
    } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
        inputStream = [task.originalRequest.HTTPBodyStream copy];
    }

    if (completionHandler) {
        completionHandler(inputStream);
    }
}
//上傳任務(wù)的回調(diào)方法
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{

    //獲取上傳的總大小途乃,如果數(shù)據(jù)不正確就從http首部中獲取
    int64_t totalUnitCount = totalBytesExpectedToSend;
    if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
        NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
        if(contentLength) {
            totalUnitCount = (int64_t) [contentLength longLongValue];
        }
    }
    //獲取task關(guān)聯(lián)的AFURLSessionManagerTaskDelegate對象
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    //如果代理對象存在,就調(diào)用代理對象的這個(gè)方法
    if (delegate) {
        [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
    }
    //如果用戶自定義回調(diào)塊存在扔傅,執(zhí)行回調(diào)塊
    if (self.taskDidSendBodyData) {
        self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
    }
}
//任務(wù)完成的回調(diào)方法
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    //同樣的套路耍共,獲取關(guān)聯(lián)的代理對象,手動調(diào)用代理對象的這個(gè)方法猎塞,執(zhí)行用戶自定義的回調(diào)塊
    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);
    }
}

以上代碼是NSURLSessionTaskDelegate的回調(diào)方法试读,通過上面的代碼可以發(fā)現(xiàn)AFURLSessionManagerTaskDelegate的作用了,AFURLSessionManager的代理方法中會根據(jù)task獲取到對應(yīng)的delegate荠耽,如果需要提前處理一些數(shù)據(jù)就先處理钩骇,處理完成后手動觸發(fā)delegate中的對應(yīng)方法,然后具體的數(shù)據(jù)處理就交由AFURLSessionManagerTaskDelegate來處理铝量。繼續(xù)看其他代理方法:

//收到服務(wù)端響應(yīng)的代理回調(diào)方法
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    //調(diào)用用戶自定義回調(diào)塊倘屹,執(zhí)行完成回調(diào)塊
    NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;

    if (self.dataTaskDidReceiveResponse) {
        disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
    }

    if (completionHandler) {
        completionHandler(disposition);
    }
}

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    if (delegate) {
        [self removeDelegateForTask:dataTask];
        [self setDelegate:delegate forTask:downloadTask];
    }

    if (self.dataTaskDidBecomeDownloadTask) {
        self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
    }
}

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{

    //獲取代理,然后調(diào)用代理的這個(gè)方法款违,有自定義回調(diào)塊就執(zhí)行
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    [delegate URLSession:session dataTask:dataTask didReceiveData:data];

    if (self.dataTaskDidReceiveData) {
        self.dataTaskDidReceiveData(session, dataTask, data);
    }
}

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
 willCacheResponse:(NSCachedURLResponse *)proposedResponse
 completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
{
    NSCachedURLResponse *cachedResponse = proposedResponse;

    if (self.dataTaskWillCacheResponse) {
        cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse);
    }

    if (completionHandler) {
        completionHandler(cachedResponse);
    }
}

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
    if (self.didFinishEventsForBackgroundURLSession) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.didFinishEventsForBackgroundURLSession(session);
        });
    }
}

上面的代碼是NSURLSessionDataDelegate的代理方法唐瀑,同樣的,如果AFURLSessionManagerTaskDelegate能響應(yīng)的關(guān)于數(shù)據(jù)處理的方法都會通過task找到對應(yīng)delegate后調(diào)用其對應(yīng)的方法插爹,然后執(zhí)行用戶自定義的回調(diào)塊哄辣,如果代理不能響應(yīng)的方法就由AFURLSessionManager自行處理请梢。

//下載任務(wù)下載文件完成后的回調(diào)方法
- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    //獲取對應(yīng)的代理對象
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
    //如果downloadTaskDidFinishDownloading回調(diào)塊存在就執(zhí)行它來獲取一個(gè)保存文件的URL路徑
    if (self.downloadTaskDidFinishDownloading) {
        NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
        //如果這個(gè)路徑存在就通過NSFileManager來移動,移動失敗發(fā)送通知
        if (fileURL) {
            delegate.downloadFileURL = fileURL;
            NSError *error = nil;
            
            if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) {
                [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
            }

            return;
        }
    }

    if (delegate) {
        [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
    }
}

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    //通過task獲取delegate
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
    //如果delegate存在就調(diào)用其該方法
    if (delegate) {
        [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
    }
    //如果回調(diào)塊存在就執(zhí)行
    if (self.downloadTaskDidWriteData) {
        self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
    }
}
//同上套路
- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
    
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
    
    if (delegate) {
        [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];
    }

    if (self.downloadTaskDidResume) {
        self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);
    }
}

到現(xiàn)在為止力穗,AFURLSessionManager所有源碼都看完了毅弧,代碼封裝了NSURLSession并提供了簡潔的創(chuàng)建NSURLSessionDataTaskNSURLSessionUploadTaskNSURLSessionDownloadTask對象的方法当窗,使用人員可以不需要考慮具體的數(shù)據(jù)處理過程够坐,最簡單的可以只通過回調(diào)塊來獲取網(wǎng)絡(luò)請求的各種信息。在具體實(shí)現(xiàn)上崖面,AFURLSessionManager通過定義AFURLSessionManagerTaskDelegate來做具體task的數(shù)據(jù)處理元咙,而AFURLSessionManager只關(guān)注于通用部分的實(shí)現(xiàn),并提供各種方法和回調(diào)塊用于處理task巫员,使得代碼結(jié)構(gòu)更清晰庶香,AFURLSessionManager代理方法結(jié)構(gòu)也更簡單。

通過源碼閱讀也可以學(xué)到AFURLSessionManager是如何使用和管理NSURLSession简识,以及相關(guān)回調(diào)方法具體實(shí)現(xiàn)細(xì)節(jié)赶掖,使用一個(gè)類就封裝了三種任務(wù)的處理方法,所以可以很便捷的使用七扰,在開發(fā)中我們經(jīng)常使用AFHTTPSessionManager奢赂,其是AFURLSessionManager的子類,所以颈走,閱讀完AFURLSessionManager源碼后膳灶,我們可以直接使用AFURLSessionManager就能很方便的進(jìn)行網(wǎng)絡(luò)請求,舉個(gè)栗子如下:

- (void)viewWillAppear:(BOOL)animated
{
    //創(chuàng)建一個(gè)AFURLSessionManager對象疫鹊,其中管理的session運(yùn)行在默認(rèn)模式下
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] init];
    
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
    //獲取一個(gè)NSURLSessionDataTask對象袖瞻,訪問百度
    NSURLSessionDataTask *task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        //請求完成后的回調(diào)
        NSLog(@"receive %@ %@ %@", response, responseObject, error);
        
    }];
    //啟動任務(wù)
    [task resume];

    //創(chuàng)建一個(gè)下載tomcat的request
    NSURLRequest *downloadRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.1/bin/apache-tomcat-9.0.1.zip"]];
    //創(chuàng)建一個(gè)下載任務(wù)
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:downloadRequest progress:^(NSProgress * _Nonnull downloadProgress) {
        //每下載一包數(shù)據(jù)就輸出一下完成情況
        NSLog(@"Download %lf", downloadProgress.fractionCompleted);
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        //演示代碼不需要存儲在磁盤中,返回nil拆吆,如有需要自行指定目錄
        return nil;
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        //完成后輸出相關(guān)信息
        NSLog(@"Download Complete %@ %@ %@", response, filePath, error);
    }];
    //啟動下載任務(wù)
    [downloadTask resume];
}

上面的栗子很簡單聋迎,就不再贅述了,有興趣的讀者可以打斷點(diǎn)看一下執(zhí)行過程是不是如源碼中講解的那般枣耀。

備注

由于作者水平有限霉晕,難免出現(xiàn)紕漏,如有問題還請不吝賜教捞奕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末牺堰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子颅围,更是在濱河造成了極大的恐慌伟葫,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件院促,死亡現(xiàn)場離奇詭異筏养,居然都是意外死亡斧抱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門渐溶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辉浦,“玉大人,你說我怎么就攤上這事茎辐∠芙迹” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵拖陆,是天一觀的道長弛槐。 經(jīng)常有香客問我,道長慕蔚,這世上最難降的妖魔是什么丐黄? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮孔飒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艰争。我一直安慰自己坏瞄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布甩卓。 她就那樣靜靜地躺著鸠匀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逾柿。 梳的紋絲不亂的頭發(fā)上缀棍,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音机错,去河邊找鬼爬范。 笑死,一個(gè)胖子當(dāng)著我的面吹牛弱匪,可吹牛的內(nèi)容都是我干的青瀑。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼萧诫,長吁一口氣:“原來是場噩夢啊……” “哼斥难!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帘饶,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤哑诊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后及刻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镀裤,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡穷当,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淹禾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馁菜。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖铃岔,靈堂內(nèi)的尸體忽然破棺而出汪疮,到底是詐尸還是另有隱情,我是刑警寧澤毁习,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布智嚷,位于F島的核電站,受9級特大地震影響纺且,放射性物質(zhì)發(fā)生泄漏盏道。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一载碌、第九天 我趴在偏房一處隱蔽的房頂上張望猜嘱。 院中可真熱鬧,春花似錦嫁艇、人聲如沸朗伶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽论皆。三九已至,卻和暖如春猾漫,著一層夾襖步出監(jiān)牢的瞬間点晴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工悯周, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粒督,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓队橙,卻偏偏與公主長得像坠陈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子捐康,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容