AFNetWorking(3.0)源碼分析(二)——AFURLSessionManager

AFNetworking是基于NSURLSession實(shí)現(xiàn)的。回想一下NSURLSession的使用方式:

創(chuàng)建NSURLSessionConfig對(duì)象
用之前創(chuàng)建的NSURLSessionConfig對(duì)象創(chuàng)建配置NSURLSession對(duì)象。
用NSURLSession對(duì)象創(chuàng)建對(duì)應(yīng)的task對(duì)象 并用resume方法執(zhí)行之。
用delegate方法或completion block 響應(yīng)網(wǎng)絡(luò)事件及數(shù)據(jù)。
對(duì)應(yīng)于每次網(wǎng)絡(luò)會(huì)話(這里可以簡(jiǎn)單理解為一個(gè)網(wǎng)頁),對(duì)應(yīng)一個(gè)NSURLSession對(duì)象,而每個(gè)會(huì)話,可以生成若干task對(duì)象用于數(shù)據(jù)的交互。

而在AFNet中, AFURLSessionManager作為核心類,封裝并提供了上述網(wǎng)絡(luò)交互功能。

AFURLSessionManager組成

AFNet運(yùn)用了組合的設(shè)計(jì)模式,將不同功能搭建成AFURLSessionManager的功能。
AFURLSessionManager的主要屬性:

/**
The managed session.
*/
@property (readonly, nonatomic, strong) NSURLSession *session;

/**
The operation queue on which delegate callbacks are run.
*/
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

/**
Responses sent from the server in data tasks created with dataTaskWithRequest:success:failure: and run using the GET / POST / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of AFJSONResponseSerializer.

@warning responseSerializer must not be nil.
*/
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;

///-------------------------------
/// @name Managing Security Policy
///-------------------------------

/**
The security policy used by created session to evaluate server trust for secure connections. AFURLSessionManager uses the defaultPolicy unless otherwise specified.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

if !TARGET_OS_WATCH

///--------------------------------------
/// @name Monitoring Network Reachability
///--------------------------------------

/**
The network reachability manager. AFURLSessionManager uses the sharedManager by default.
*/
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;

endif

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

/**
The data, upload, and download tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;

/**
The data tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;

/**
The upload tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;

/**
The download tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

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

/**
The dispatch queue for completionBlock. If NULL (default), the main queue is used.
*/
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;

/**
The dispatch group for completionBlock. If NULL (default), a private dispatch group is used.
*/
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

AFNet的注釋很詳細(xì),其屬性可以作如下分類

AFURLSessionManager所管理的Session對(duì)象
@property (readonly, nonatomic, strong) NSURLSession *session;

delegate所返回的NSOperationQueue
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

解析網(wǎng)絡(luò)返回?cái)?shù)據(jù)的對(duì)象(遵循AFURLResponseSerialization協(xié)議)
@property (nonatomic, strong) id responseSerializer;

用于處理網(wǎng)絡(luò)連接安全處理策略的AFSecurityPolicy對(duì)象
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

用于檢測(cè)網(wǎng)絡(luò)數(shù)據(jù)的AFNetworkReachabilityManager對(duì)象
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;

當(dāng)前的Session task
*tasks;

*dataTasks;

*uploadTasks;

*downloadTasks;

設(shè)置Call back隊(duì)列
在這里除了能設(shè)置Session的completion block外(默認(rèn)為main block),還可以設(shè)置completion group。

看過這些分類,是不是覺得AFURLSessionManager也不是多么復(fù)雜了?確實(shí),AFNet本就是一套簡(jiǎn)潔的網(wǎng)絡(luò)框架,功能強(qiáng)大而結(jié)構(gòu)清晰。
下面,我們就一起看一看,利用AFURLSessionManager是如何完成一次簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求的。

運(yùn)用AFURLSessionManager完成網(wǎng)絡(luò)請(qǐng)求

運(yùn)用AFRULSessionManager獲取網(wǎng)絡(luò)數(shù)據(jù),僅需如下幾個(gè)步驟:

// step1. 初始化AFURLSessionManager對(duì)象
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

// step2. 獲取AFURLSessionManager的task對(duì)象
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Get Net data success!");
}
}];

// step3. 發(fā)動(dòng)task
[dataTask resume];

OK,簡(jiǎn)單的三步,就完成了對(duì)網(wǎng)絡(luò)數(shù)據(jù)的請(qǐng)求。

下面我們就一步步分析,這三步背后AFNet的源代碼是如何實(shí)現(xiàn)的。

初始化AFURLSessionManager

要進(jìn)行網(wǎng)絡(luò)請(qǐng)求,第一步就是初始化AFURLSessionManager,調(diào)用函數(shù)

  • (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration
    1
    該函數(shù)很簡(jiǎn)單,只有一個(gè)NSURLSessionConfiguration用來配置AFURLSessionManager所管理的NSURLSession對(duì)象。

它的實(shí)現(xiàn)代碼如下:

(instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
// =============== 設(shè)置NSURLSession ===============
// 若configuration為nil,則采用默認(rèn)defaultSessionConfiguration

if (!configuration) {
    configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}

self.sessionConfiguration = configuration;
// session 的delegate callback queue, 最大并發(fā)為1 
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
// 初始化所管理的session
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

// =============== 設(shè)置response 數(shù)據(jù)序列化 ===============
self.responseSerializer = [AFJSONResponseSerializer serializer];

// =============== 設(shè)置網(wǎng)絡(luò)安全策略 ===============
self.securityPolicy = [AFSecurityPolicy defaultPolicy];

// =============== 設(shè)置網(wǎng)絡(luò)狀態(tài)監(jiān)控Manager(注意這里是一個(gè)全局單例實(shí)現(xiàn)) ===============

if !TARGET_OS_WATCH

self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];

endif

// =============== 設(shè)置存儲(chǔ)NSURL task與AFURLSessionManagerTaskDelegate的詞典(重點(diǎn),在AFNet中,每一個(gè)task都會(huì)被匹配一個(gè)AFURLSessionManagerTaskDelegate 來做task的delegate事件處理) ===============
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

// =============== 設(shè)置AFURLSessionManagerTaskDelegate 詞典的鎖,確保詞典在多線程訪問時(shí)的線程安全===============
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;

// =============== 為所管理的session的所有task設(shè)置完成塊(這里不是很明白,既然是初始化函數(shù),那么應(yīng)該沒有任何task在運(yùn)行才是,怎么需要在這里設(shè)置完成塊呢???)===============
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}

    for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
        [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
    }

    for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
        [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
    }
}];

// =============== 返回初始化好的self ===============
return self;
}
這就是AFURLSessionManager的初始化函數(shù),主要是對(duì)其屬性進(jìn)行初始化,要注意的是它的私有屬性

@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;

@property (readwrite, nonatomic, strong) NSLock *lock;

AFURLSessionManager會(huì)為每一個(gè)所管理的task對(duì)應(yīng)創(chuàng)建一個(gè)AFURLSessionManagerTaskDelegate對(duì)象,Manager會(huì)交ManagerTaskDelegate對(duì)象由來具體處理各個(gè)task事物,從而實(shí)現(xiàn)了同一個(gè)AFURLSessionManager對(duì)多個(gè)task的管理。

生成AFURLSessionManager的task對(duì)象

當(dāng)初始化好AFURLSessionManager后,就需要獲取一個(gè)代表我們當(dāng)前網(wǎng)絡(luò)請(qǐng)求的task了:

/**
Creates an NSURLSessionDataTask with the specified request.

@param request The HTTP request for the request.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/

  • (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
    completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

當(dāng)然還可以獲取download task 和upload task, 這里我們僅分析最簡(jiǎn)單的data task。

其實(shí)現(xiàn)如下:

return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
1
僅一行代碼,調(diào)用自身另一方法:

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

    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
    dataTask = [self.session dataTaskWithRequest:request];
    });

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

    return dataTask;
    }

上述方法完成了兩件事情:

  1. 生成一個(gè)data task對(duì)象,并返回。
  2. 為該data task對(duì)象生成一個(gè)匹配的AFURLSessionManagerTaskDelegate對(duì)象,并關(guān)聯(lián)之。

對(duì)于功能1,沒什么多說的,就是這里AFNet為了避免iOS 8.0以下版本中偶發(fā)的taskIdentifiers不唯一的bug,AFNet使用了

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

函數(shù)創(chuàng)建task對(duì)象。

其實(shí)現(xiàn)應(yīng)該是因?yàn)閕OS 8.0以下版本中會(huì)并發(fā)地創(chuàng)建多個(gè)task對(duì)象,而同步有沒有做好,導(dǎo)致taskIdentifiers 不唯一…

對(duì)于功能二,AFNet為每一個(gè)task生成對(duì)應(yīng)的task delegate對(duì)象,我們則應(yīng)該重點(diǎn)了解一下。

  • (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
    uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
    downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
    completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
    {
    // 創(chuàng)建AFURLSessionManagerTaskDelegate對(duì)象
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    // AFURLSessionManagerTaskDelegate與AFURLSessionManager建立相互關(guān)系
    delegate.manager = self;
    // 設(shè)置AF delegate的完成塊為用戶傳入的完成塊
    delegate.completionHandler = completionHandler;
    // 設(shè)置dataTask的taskDescription
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    // ***** 將AF delegate對(duì)象與 dataTask建立關(guān)系
    [self setDelegate:delegate forTask:dataTask];
    // 設(shè)置AF delegate的上傳進(jìn)度,下載進(jìn)度塊。
    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
    }

AFNet通過封裝AFURLSessionManagerTaskDelegate對(duì)象,對(duì)每個(gè)task 進(jìn)行管理,而AFURLSessionManager僅需要管理建立task 與AF delegate的詞典即可,實(shí)現(xiàn)了AFURLSessionManager功能的下放。
那么我們這里重點(diǎn)看一下,AF delegate與task是如何建立關(guān)系的:

[self setDelegate:delegate forTask:dataTask];

實(shí)現(xiàn):

  • (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
    forTask:(NSURLSessionTask *)task
    {
    NSParameterAssert(task);
    NSParameterAssert(delegate);
    // 加鎖,確保詞典的線程安全
    [self.lock lock];
    // 將AF delegate放入以taskIdentifier標(biāo)記的詞典中(同一個(gè)NSURLSession中的taskIdentifier是唯一的)
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    // 為AF delegate 設(shè)置task 的progress監(jiān)聽
    [delegate setupProgressForTask:task];
    [self addNotificationObserverForTask:task];
    // 詞典操作完畢,解鎖
    [self.lock unlock];
    }

AFURLSessionManager會(huì)將每個(gè)AF delegate放入其詞典中,同時(shí),AF delegate會(huì)監(jiān)聽每個(gè)task的進(jìn)度,這是通過

[delegate setupProgressForTask:task];

實(shí)現(xiàn)的。我們繼續(xù)看 AF delegate 是如何監(jiān)聽task的各種進(jìn)度的:

pragma mark - NSProgress Tracking

  • (void)setupProgressForTask:(NSURLSessionTask *)task {
    __weak typeof(task) weakTask = task;

    self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
    [self.uploadProgress setCancellable:YES];
    [self.uploadProgress setCancellationHandler:^{
    typeof(weakTask) strongTask = weakTask;
    [strongTask cancel];
    }];
    [self.uploadProgress setPausable:YES];
    [self.uploadProgress setPausingHandler:^{
    typeof(weakTask) strongTask = weakTask;
    [strongTask suspend];
    }];
    if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
    [self.uploadProgress setResumingHandler:^{
    typeof(weakTask) strongTask = weakTask;
    [strongTask resume];
    }];
    }

    [self.downloadProgress setCancellable:YES];
    [self.downloadProgress setCancellationHandler:^{
    typeof(weakTask) strongTask = weakTask;
    [strongTask cancel];
    }];
    [self.downloadProgress setPausable:YES];
    [self.downloadProgress setPausingHandler:^{
    typeof(weakTask) strongTask = weakTask;
    [strongTask suspend];
    }];

    if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
    [self.downloadProgress setResumingHandler:^{
    typeof(weakTask) strongTask = weakTask;
    [strongTask resume];
    }];
    }

    // 這里為什么要用NSStringFromSelector 而不直接使用NSString???
    [task addObserver:self
    forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
    options:NSKeyValueObservingOptionNew
    context:NULL];
    [task addObserver:self
    forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
    options:NSKeyValueObservingOptionNew
    context:NULL];

    [task addObserver:self
    forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
    options:NSKeyValueObservingOptionNew
    context:NULL];
    [task addObserver:self
    forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
    options:NSKeyValueObservingOptionNew
    context:NULL];

    [self.downloadProgress addObserver:self
    forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
    options:NSKeyValueObservingOptionNew
    context:NULL];
    [self.uploadProgress addObserver:self
    forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
    options:NSKeyValueObservingOptionNew
    context:NULL];
    }

上面的代碼可以分為兩個(gè)部分,

  1. 設(shè)置AF delegate的uploadProgress 和 downloadProgress。(注意為了防止對(duì)block對(duì)象截取產(chǎn)生的循環(huán)引用,將傳入的task設(shè)置為了weak。但是這里的循環(huán)引用在哪里呢??? 其實(shí)這里鑒于block所造成的一系列循環(huán)引用的問題,AFNet采取了一種防御式編程的方法,對(duì)于沒有必要在block中進(jìn)行強(qiáng)引用的變量,一律采用弱引用。并且,當(dāng)task置為nil后,block也沒有理由繼續(xù)strong引用task變量)
  2. 利用KVO, 監(jiān)聽task屬性及uploadProgress,downloadProgress屬性的變化,進(jìn)一步監(jiān)聽task的數(shù)據(jù)傳輸進(jìn)程。

看到了KVO,那我們就直接看其對(duì)應(yīng)的響應(yīng)函數(shù):

  • (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([object isKindOfClass:[NSURLSessionTask class]]) {
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
    self.downloadProgress.completedUnitCount = [change[@"new"] longLongValue];
    } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
    self.downloadProgress.totalUnitCount = [change[@"new"] longLongValue];
    } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
    self.uploadProgress.completedUnitCount = [change[@"new"] longLongValue];
    } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
    self.uploadProgress.totalUnitCount = [change[@"new"] longLongValue];
    }
    }
    else if ([object isEqual:self.downloadProgress]) {
    if (self.downloadProgressBlock) {
    self.downloadProgressBlock(object);
    }
    }
    else if ([object isEqual:self.uploadProgress]) {
    if (self.uploadProgressBlock) {
    self.uploadProgressBlock(object);
    }
    }
    }

很簡(jiǎn)單,當(dāng)監(jiān)控的Task屬性改變時(shí),同時(shí)改變由AF delegate所管理持有的Progress對(duì)象的屬性。
同時(shí),當(dāng)AF delegate的Progress對(duì)象屬性改變時(shí),調(diào)用對(duì)應(yīng)的progress block。

NSURLSessionDelegate 的響應(yīng)

因?yàn)锳FURLSessionManager所管理的NSURLSession對(duì)象的delegate被設(shè)置為AFURLSessionManager自身,因此所有的NSURLSessionDelegate回調(diào)方法的目的地都是AFURLSessionManager,而AFURLSessionManager又會(huì)根據(jù)是否需要具體處理,會(huì)將屬于AF delegate要響應(yīng)的delegate,傳遞到對(duì)應(yīng)的AF delegate去。
AFURLSessionManager 和 AFURLSessionManagerTaskDelegate 相應(yīng)的delegate回調(diào)方法如下:

AFURLSessionManager 需要處理的NSURLSessionDelegate:
這里寫圖片描述

AFURLSessionManagerTaskDelegate 需要處理的NSURLSessionDelegate:
這里寫圖片描述

當(dāng)AFURLSessionManager 覺得應(yīng)該有AF delegate來處理該事件時(shí),會(huì)取出對(duì)應(yīng)task的delegate,并將該事件原封不動(dòng)的傳遞到delegate。
其實(shí)細(xì)看AF delegate所實(shí)現(xiàn)的NSURLSessionDelegate也不多,僅三條:

-URLSession:task:didCompleteWithError:
-URLSession:dataTask:didReceiveData:
-URLSession:downloadTask:didFinishDownloadingToURL:

可以看出,屬于AF task delegate處理的回調(diào),兩條是對(duì)于completion的處理,另一條則是對(duì)于每個(gè)task,分別接受并記錄其receive data。

而AFURLSessionManager對(duì)于NSSession的回調(diào)處理相對(duì)簡(jiǎn)單,不外乎兩步:

  1. 如果有對(duì)應(yīng)的user block,則將當(dāng)前NSSession block傳遞至user block(此處可能會(huì)利用user block的返回值,來繼續(xù)下一步操作)。
  2. 如果需要AF task delegate處理,則將該回調(diào)事件傳給相應(yīng)的AF task delegate。

我們可以看下面幾個(gè)例子:

  • (void)URLSession:(NSURLSession *)session
    task:(NSURLSessionTask *)task
    willPerformHTTPRedirection:(NSHTTPURLResponse *)response
    newRequest:(NSURLRequest *)request
    completionHandler:(void (^)(NSURLRequest *))completionHandler
    {
    NSURLRequest *redirectRequest = request;
    // step1. 看是否有對(duì)應(yīng)的user block
    if (self.taskWillPerformHTTPRedirection) {
    redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
    }

    if (completionHandler) {
    // step2. 運(yùn)用user block返回值或是原始值,使NSSession事件繼續(xù)
    completionHandler(redirectRequest);
    }
    }

  • (void)URLSession:(NSURLSession *)session
    task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error
    {
    // step1. 應(yīng)交由AF task delegate處理的事件,取出對(duì)應(yīng)AF task delegate,
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

    // delegate may be nil when completing a task in the background
    if (delegate) {
    // step2. 將事件交由AF task delegate處理
    [delegate URLSession:session task:task didCompleteWithError:error];
    // NOTE: 此處是session task最終的回調(diào)函數(shù),task不會(huì)再返回任何信息。因此刪除對(duì)應(yīng)的AF task delegate
    [self removeDelegateForTask:task];
    }
    // step3. 若有對(duì)應(yīng)的user block,則調(diào)用之
    if (self.taskDidComplete) {
    self.taskDidComplete(session, task, error);
    }
    }

AFURLSessionManager 與 AFURLSessionManagerTaskDelegate 的分工

到這里我們可以想一想,既然NSURLSession的delegate是AFURLSessionManager對(duì)象,那么為什么不在AFURLSessionManager中處理所有的事件回調(diào),搞出來一個(gè)AFURLSessionManagerTaskDelegate干什么?

我們知道,NSURLSession的回調(diào)有很多,而當(dāng)我們啟動(dòng)一個(gè)task,真正想要獲取的信息是什么呢?就是網(wǎng)絡(luò)請(qǐng)求最終所返回的數(shù)據(jù)(我所進(jìn)行的網(wǎng)絡(luò)操作成功或是失敗,服務(wù)器為我返回的數(shù)據(jù))唄! 其它的回調(diào),什么認(rèn)證質(zhì)詢,task需要新的body stream,什么request即將重定向, 統(tǒng)統(tǒng)都是浮云,都是為了我們能夠最終獲取到服務(wù)器返回的數(shù)據(jù)所服務(wù)的。

另外我們也想要知道我們的網(wǎng)絡(luò)請(qǐng)求的進(jìn)度。
總結(jié)為兩點(diǎn):

  1. 獲取最終返回?cái)?shù)據(jù)
  2. 獲知當(dāng)前請(qǐng)求的進(jìn)度

于是,AFNetWorking 便在紛繁復(fù)雜的回調(diào)處理中,特意抽象出AFURLSessionManagerTaskDelegate,用于應(yīng)付網(wǎng)絡(luò)返回?cái)?shù)據(jù)的處理(包括保存中間值,序列化返回值,錯(cuò)誤處理)和網(wǎng)絡(luò)請(qǐng)求進(jìn)度。
這樣做可以使代碼結(jié)構(gòu)更分明,邏輯更清晰。
這在AFURLSessionManagerTaskDelegate的聲明中也可以看出一二, 其屬性按功能分類就兩種,一種用來保存服務(wù)器返回?cái)?shù)據(jù)及completion回調(diào),另一種就是反應(yīng)當(dāng)前網(wǎng)絡(luò)處理進(jìn)度:

@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
@property (nonatomic, weak) AFURLSessionManager *manager;
@property (nonatomic, strong) NSMutableData *mutableData; // 保存服務(wù)器返回的數(shù)據(jù)
@property (nonatomic, strong) NSProgress *uploadProgress; // 上傳進(jìn)度
@property (nonatomic, strong) NSProgress *downloadProgress; // 下載進(jìn)度
@property (nonatomic, copy) NSURL *downloadFileURL; // 下載文件目的存儲(chǔ)地址
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 說到AFNetwokring這個(gè)強(qiáng)大第三方網(wǎng)絡(luò)請(qǐng)求庫,大家應(yīng)該都不陌生吧,ios開發(fā)、mac開發(fā)都經(jīng)常用,主要是他...
    塵峰的小孩閱讀 521評(píng)論 0 0
  • 本篇是AFNetworking 3.0源碼解讀的第五篇了。 AFNetworking 3.0 源碼解讀(一)之 A...
    泥孩兒0107閱讀 610評(píng)論 0 0
  • 概述 上一篇主要分析了基于NSURLConnection的AFURLConnectionOperation,本篇主...
    egoCogito_panf閱讀 2,110評(píng)論 0 13
  • 聲明:以下是對(duì)所看源碼和相關(guān)資料的整理 框架組成 AFNetworking作為開發(fā)中使用最多的第三方網(wǎng)絡(luò)庫,功能完...
    jinstar520閱讀 491評(píng)論 0 0
  • 建議去看原文 AFURLSessionManager _AFURLSessionTaskSwizzling 當(dāng)時(shí)看...
    泥孩兒0107閱讀 648評(píng)論 0 0

友情鏈接更多精彩內(nèi)容