1. 程式人生 > >AFNetWorking3.2.0原始碼閱讀-AFURLSessionManager(二)

AFNetWorking3.2.0原始碼閱讀-AFURLSessionManager(二)

AFNetWorking3.2.0原始碼閱讀-AFURLSessionManager(二)

AFURLSessionManager.m 檔案內容解析

Define


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; } static void url_session_manager_create_task_safely(dispatch_block_t block) { if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) { // Fix of bug // Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093 dispatch_sync(url_session_manager_creation_queue(), block); } else { block(); } }

這兩個方法是用C語言的寫法封裝了一個用來解決在iOS 8及之前task執行block時崩潰的問題。

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

進度佇列,這個佇列用在請求結果返回後處理時,保證在處理返回結果的時候時是非同步的。

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

請求完成處理事務組,將請求完成後的結果(無論成功還是失敗)回撥放在 url_session_manager_completion_group 中的 指定佇列或者主佇列中去做,對應結果的通知也是在這裡邊做的。

dispatch_group_t 一般我們是用來操作一組相關的任務,在其中做任務之間同步和資料傳遞操作,還可以方便我們管理一組任務的狀態,但是他在這裡並沒有做任何關於同步的動作,只是單純新增進去了,我們暫且猜測他會在其他地方會用到這些功能,或者更有深意。


AFURLSessionManagerTaskDelegate

<NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>

這個類從名字和遵守的協議我們很容易得知它是一個網路請求的代理方法處理類

Property

@property (nonatomic, weak) AFURLSessionManager *manager;

被代理的mangerweak防止迴圈引用

@property (nonatomic, strong) NSMutableData *mutableData;

NSURLSessionTaskDelegateURLSession:task:didCompleteWithError:方法中拼接下載的資料。

// 上傳進度
@property (nonatomic, strong) NSProgress *uploadProgress;
// 下載進度
@property (nonatomic, strong) NSProgress *downloadProgress;
// 下載檔案儲存路徑
@property (nonatomic, copy) NSURL *downloadFileURL;
// 完成下載回撥
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
// 上傳進度回撥
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
// 下載進度回撥
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
// 請求完成回撥
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;



Life Cycle Method

Init


- (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];

    __weak __typeof__(task) weakTask = task;
    for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ])
    {
        progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
        progress.cancellable = YES;
        progress.cancellationHandler = ^{
            [weakTask cancel];
        };
        progress.pausable = YES;
        progress.pausingHandler = ^{
            [weakTask suspend];
        };
#if AF_CAN_USE_AT_AVAILABLE
        if (@available(iOS 9, macOS 10.11, *))
#else
        if ([progress respondsToSelector:@selector(setResumingHandler:)])
#endif
        {
            progress.resumingHandler = ^{
                [weakTask resume];
            };
        }

        [progress addObserver:self
                   forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                      options:NSKeyValueObservingOptionNew
                      context:NULL];
    }
    return self;
}

初始化方法功能:
- _mutableData _uploadProgress _downloadProgress初始化。
- _uploadProgress _downloadProgress 新增resumingHandler pausingHandlerblock。
- _uploadProgress _downloadProgress 新增對 fractionCompleted key值變化的監聽並反饋到downloadProgressBlock uploadProgressBlock方法中。

NSURLSessionTaskDelegate

- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error

在這個代理方法中處理了請求響應

注意點:
- 1.使用userInfo可變字典儲存responseSerializer downloadFileURL mutableData error responseObject serializationError , 並將其在錯誤/成功的時候發出AFNetworkingTaskDidCompleteNotification通知
- 2.在錯誤/成功的回撥中使用dispatch_group_async 在指定或者預設的組中將處理放入指定或者主佇列做操作集中處理,
- 3,在呼叫完成回撥completionHandlerblock後,在主執行緒中啟用非同步操作傳送1中的userInfo到AFNetworkingTaskDidCompleteNotification通知


NSURLSessionDataDelegate

// 收到data回撥
- (void)URLSession:(__unused NSURLSession *)session
          dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
    self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;

    [self.mutableData appendData:data];
}
  • 1,在這個方法中更新downloadProgresstotalUnitCount completedUnitCount,更新時會改變其fractionCompleted,因在manager初始化中對fractionCompleted做了KVO,所以會觸發NSProgress Tracking。
  • 2,返回資料拼接到self.mutableData
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{

    self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    self.uploadProgress.completedUnitCount = task.countOfBytesSent;
}

上傳資料的進度更新,套路同上一個方法


NSURLSessionDownloadDelegate

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

    self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
    self.downloadProgress.completedUnitCount = totalBytesWritten;
}

更新下載進度,通過通知呼叫進度的回撥,套路同上


- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{

    self.downloadProgress.totalUnitCount = expectedTotalBytes;
    self.downloadProgress.completedUnitCount = fileOffset;
}

更新重新(斷電續傳)下載進度,通過通知呼叫進度的回撥,套路同上

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    self.downloadFileURL = nil;

    if (self.downloadTaskDidFinishDownloading) {
        self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
        if (self.downloadFileURL) {
            NSError *fileManagerError = nil;

            if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
                [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
            }
        }
    }
}

完成下載回撥
- 1,downloadTaskDidFinishDownloadingblock實現的情況下,通過它獲取到下載的downloadFileURL。
- 2,downloadFileURL獲取成功將臨時檔案移動到downloadFileURL目錄中。
- 3,如果檔案移動成功傳送AFURLSessionDownloadTaskDidFailToMoveFileNotification通知,將當前下載的downloadTask 作為Object,fileManagerError.userInfo作為userInfo傳送出去。

_AFURLSessionTaskSwizzling

這裡因為!(這個bug)[https://github.com/AFNetworking/AFNetworking/pull/2702]
做了方法置換的處理,大體的原因時因為在iOS7,iOS8的時候NSURLSession的結構發生了變化

AFURLSessionManager @interface()

@property

屬性內容和.h檔案中的Set方法基本一致,不需過多解釋
在這我們可以看到一個寫法:
我們常見的一種場景
@interface中對外暴露一個屬性的只讀屬性,但是在@implementation中需要對其進行更改。

AFN中的寫法是在@interface中用(readonly)修飾,在Extension中使用readwrite修飾
官方文件上也是這麼建議的 !(Use Class Extensions to Hide Private Information)[https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html#//apple_ref/doc/uid/TP40011210-CH6-SW3]

當然我們還有其他的方式
比如直接在@implementation使用_iVar進行更改操作
還可以使用 @synthesize someVar = _someVar
// TODO:1,readonly 和 readwrite修飾符做了什麼,使用readonly的時候有沒有產生set方法?
// 2,為什麼@synthesize someVar = _someVar之後就可以更改被readonly修飾的屬性?

AFURLSessionManager @implementation

Init

// 重寫init,呼叫指定初始化方法`initWithSessionConfiguration`
- (instancetype)init {
    return [self initWithSessionConfiguration:nil];
}

// 真正的初始化方法
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    // 預設configuration設定
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    self.sessionConfiguration = configuration;

     // 操作佇列初始化,預設最大併發數為1
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    // session 初始化,使用剛剛初始化的操作佇列和sessionConfiguration
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

     // 預設的響應格式化器為JSON
    self.responseSerializer = [AFJSONResponseSerializer serializer];
     // 預設的加密設定
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];
     // 非WATCH環境設定網路監聽
#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
      // 設定 Task和代理關係的記錄dictionary
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    // 初始化鎖
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

      // 將當前session中的所有task設定對應的代理
    [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;
}


dealloc

// 移除所有的通知監聽,釋放物件
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


addDelegateFor…Task

給data,upload,download task 設定代理等操作

// 設定data task
- (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
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
                        progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
               completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    uploadTask.taskDescription = self.taskDescriptionForSessionTasks;

    [self setDelegate:delegate forTask:uploadTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
}

- (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] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

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

這三個方法大體步驟是一樣的,無非就是設定各種回撥block,方法代理等
有幾個點我們需要注意:

delegate.manager = self;

這裡delegate 是一個 AFURLSessionManagerTaskDelegate 的區域性變數,delegate.manager是一個AFURLSessionManager型別的物件,在AFURLSessionManagerTaskDelegateclass中使用weak關鍵字描述,是為了迴圈引用,因為delegate.manager = self;中self就是AFURLSessionManager型別的物件。

dataTask.taskDescription = self.taskDescriptionForSessionTasks;

.taskDescriptionForSessionTasks是一個get方法


- (NSString *)taskDescriptionForSessionTasks {
    return [NSString stringWithFormat:@"%p", self];
}

格式控制符“%p”中的p是pointer(指標)的縮寫,所以給task設定的描述是本類物件為一的指標值

[self setDelegate:delegate forTask:dataTask];

這個方法的實現:


- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
     // 判空
    NSParameterAssert(task);
    NSParameterAssert(delegate);

   // 鎖
    [self.lock lock];

   // 此字典記錄所有task和他的代理(delegate,一個AFURLSessionManagerTaskDelegate類物件)的對應關係,是一個key-value的格式
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;

   // 設定進度相關的操作
    [delegate setupProgressForTask:task];

   // 新增啟動和暫停的監聽
    [self addNotificationObserverForTask:task];

   // 開鎖
    [self.lock unlock];
}

啟動/暫停


- (void)taskDidResume:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;

   // 是否有   `taskDescription`方法
    if ([task respondsToSelector:@selector(taskDescription)]) {

            // 如果有,是否是當前這個物件
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {

                 // 如果是,傳送task resume 的通知
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
            });
        }
    }
}

- (void)taskDidSuspend:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;

    // 是否有`taskDescription`方法
    if ([task respondsToSelector:@selector(taskDescription)]) {

        // 如果有,是否是當前這個物件
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {

            // 如果是,傳送task suspend 的通知
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
            });
        }
    }
}

get/remove Delegete For Task

// 獲取task對應的delegate , 是 `- setDelegate:foTask:` 方法的你操作,也會加鎖,因為在併發情況下,可能會出現資料同步問題
- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = nil;
    [self.lock lock];
    delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
    [self.lock unlock];

    return delegate;
}

// 刪除task的delegate
- (void)removeDelegateForTask:(NSURLSessionTask *)task {
    // 判空
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    [self.lock lock];

    // 清除進度回撥
    [delegate cleanUpProgressForTask:task];
    // 清除監聽
    [self removeNotificationObserverForTask:task];
    // 在記錄表中清除task的記錄
    [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
    [self.lock unlock];
}

獲取各種tasks

- (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)];
}

不難看出,核心方法是 -tasksForKeyPath:


- (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"];
        }

        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    return tasks;
}

這裡需要我們注意的是用到了dispatch的訊號量,這是因為getTasksWithCompletionHandler是一個非同步操作:官方文件

invalidateSeesionCancelingTasks:

- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (cancelPendingTasks) {
                 // 立即取消所有任務
            [self.session invalidateAndCancel];
        } else {
                 // 立即returns,但是並不會回影響正在執行的任務,它們會繼續執行到結束
            [self.session finishTasksAndInvalidate];
        }
    });
}

// TODO:這裡有個放在主執行緒操作的程式碼,不知道是為了什麼著想,想必是為了安全,有大牛來給解答一下?

Send Request

data task request

// interface
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
}

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {

    __block NSURLSessionDataTask *dataTask = nil;

    // 解決iOS 8 及其以下版本的bug
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

__block 修飾符的背後究竟發生了什麼,為什麼用它修飾就可以在block中更改?
為什麼不用它修飾就不能在block中更改?,這個問題我在之前的blog中寫過,請看:Block截獲自動變數實現與__block修飾符內部實現

upload task request

uploadTaskWithRequest:fromFile:


- (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 為 nil, 並且 self.attemptsToRecreateUploadTasksForBackgroundSessions == YES, 並且 self.session.configuration.identifier存在的情況下
    // 嘗試重新建立uploadTask,最多嘗試3次
    // 這個操作是因為在iOS7以下版本會出現background情況下upload有時會變成nil
    if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
        for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
            uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
        }
    }

    [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


- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                                        completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler

對data,和stream的請求我們不用詳細探究

download task request


- (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


- (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

download task和upload task操作幾乎一摸一樣

get upload/download progress for task

- (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task {
    return [[self delegateForTask:task] uploadProgress];
}

- (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task {
    return [[self delegateForTask:task] downloadProgress];
}

看明白delegateForTask:方法即可

NSObject

// 過載description方法便於在NSLog的時候獲取更具像化的資訊
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue];
}
// 過載是否可以響應selector的判斷方法,讓本類物件在沒有實現對應block時可以將方法響應繼續向下傳遞,而不是阻斷。
- (BOOL)respondsToSelector:(SEL)selector {
    if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
        return self.taskWillPerformHTTPRedirection != nil;
    } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
        return self.dataTaskDidReceiveResponse != nil;
    } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
        return self.dataTaskWillCacheResponse != nil;
    } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
        return self.didFinishEventsForBackgroundURLSession != nil;
    }

    return [[self class] instancesRespondToSelector:selector];
}


NSURLSessionDelegate

// 發生錯誤回撥
- (void)URLSession:(NSURLSession *)session
didBecomeInvalidWithError:(NSError *)error
{
    if (self.sessionDidBecomeInvalid) {
        self.sessionDidBecomeInvalid(session, error);
    }
      // 傳送錯誤通知
    [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}

// 發生身份驗證回撥
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;

     // 如果實現了對身份驗證的block就執行
    if (self.sessionDidReceiveAuthenticationChallenge) {
            // 執行結果
        disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
    } else {

            // 如果驗證方式是 NSURLAuthenticationMethodServerTrust ,
            // @abstract SecTrustRef validation required.  Applies to any protocol.
            // 這裡的驗證方式還有很多,請看 NSURLProtectionSpace.h 中的定義
            // [瞭解更多看這裡](https://draveness.me/afnetworking5)
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

                 // 如果我們信任這個host
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {

                //獲取證書
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

                // 如果有證書
                if (credential) {
                        // 指定的證書,可以為nil
                    disposition = NSURLSessionAuthChallengeUseCredential;
                } else { 如果沒有證書
                       // 使用預設的處理,如果這個代理方法沒有實現,將會忽略這個證書引數
                    disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                }
            } else {
                    // 拒絕
                disposition = NSURLSessionAuthChallengeRejectProtectionSpace;
            }
        } else {
                 // 使用預設的處理,如果這個代理方法沒有實現,將會忽略這個證書引數 
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

      // 完成身份驗證後的回撥block
    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

NSURLSessionTaskDelegate

// 處理重定向操作,
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest *))completionHandler
{
    NSURLRequest *redirectRequest = request;

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

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

什麼是重定向

// 這裡和NSURLSessionDelegate 中同樣有個認證回撥,區別就在於,這裡並沒有針對獲取證書是否成功做disposition的對應處理,看樣子是預設證書一定會獲取成功,這裡稍微有點懵逼,有大神指正沒有?
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;
請求輸入流回調
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
{
    NSInputStream *inputStream = nil;

     // 如果self.taskNeedNewBodyStream實現
     if (self.taskNeedNewBodyStream) {

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

            // 如果task.originalRequest.HTTPBodyStream存在 ,並且遵循了NSCopying協議
            // 因為HTTPBodyStream不是執行緒安全的,所以在使用的時候需要copy
        inputStream = [task.originalRequest.HTTPBodyStream copy];
    }

    if (completionHandler) {
        completionHandler(inputStream);
    }
}
// 已經發送的資料回撥
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{

    int64_t totalUnitCount = totalBytesExpectedToSend;
    if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
            // 用KVC的方式獲取內容長度
        NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
        if(contentLength) {
            totalUnitCount = (int64_t) [contentLength longLongValue];
        }
    }

    if (self.taskDidSendBodyData) {
        self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
    }
}
// 完成
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

    // delegate may be nil when completing a task in the background
    if (delegate) {
        [delegate URLSession:session task:task didCompleteWithError:error];

        [self removeDelegateForTask:task];
    }

    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }
}


NSURLSessionDataDelegate

// 完成
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;

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

    if (comple