前言
在上篇AFNetworking源碼閱讀2——核心快結(jié)尾時(shí),解釋了為什么在AFURLSessionManager類中實(shí)現(xiàn)了session和 session task的代理方法,還要在AFURLSessionManagerTaskDelegate代理類中再實(shí)現(xiàn)一遍session task的代理方法?AFURLSessionManagerTaskDelegate代理類存在的意義是什么?
原因我們已經(jīng)知道,是將我們請(qǐng)求所得的數(shù)據(jù),或感興趣的信息等抽離在一個(gè)專門類中。然后再以此類回調(diào)給使用者調(diào)用的方法,回饋給使用者。
該代理類的作用基本就是這樣,但我們還是需要看看具體實(shí)現(xiàn),學(xué)習(xí)學(xué)習(xí)。
源碼
先看頭文件:

@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
@property (nonatomic, weak) AFURLSessionManager *manager;
@property (nonatomic, strong) NSMutableData *mutableData;
@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;
@end
首先可以看到該類是實(shí)現(xiàn)了session task的三個(gè)協(xié)議的。manager意為對(duì)應(yīng)的AFURLSessionManager實(shí)例;mutableData意為從網(wǎng)絡(luò)返回的數(shù)據(jù);uploadProgress和downloadProgress意為上傳進(jìn)度和下載進(jìn)度;downloadFileURL意為所下載文件的磁盤路徑;后面幾個(gè)是定義的block屬性,顧名思義,它們分別代表下載完成后的回調(diào)block,上傳進(jìn)度發(fā)生改變時(shí)的回調(diào)block,下載進(jìn)度發(fā)生改變時(shí)的回調(diào)block,完成后的處理回調(diào)block。它們的類型定義如下,留心其返回值和參數(shù)。
typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
接下來(lái)該類具體怎么實(shí)現(xiàn)的:

可以看到,該類的結(jié)構(gòu)比較簡(jiǎn)單,篇幅也不長(zhǎng)。主要有三部分:初始化,進(jìn)度跟蹤,代理方法的實(shí)現(xiàn)。我們按順序來(lái),先看看初始化方法:
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
self.mutableData = [NSMutableData data];
self.uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.uploadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
self.downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.downloadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
return self;
}
初始化方法沒(méi)什么可說(shuō)的,主要是在其中初始化了屬性。
接著看對(duì)task對(duì)應(yīng)的進(jìn)度追蹤代碼:
#pragma mark - NSProgress Tracking
/*
主要是設(shè)置兩個(gè)NSProgress類型變量的uploadProgress和downloadProgress屬性
*/
- (void)setupProgressForTask:(NSURLSessionTask *)task {
__weak __typeof__(task) weakTask = task;
self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
/*
下面設(shè)置了uploadProgress和downloadProgress的三個(gè)屬性:cancel/pause/resume。正好對(duì)應(yīng)session task的cancel/pause/resume三個(gè)狀態(tài)。也就是說(shuō)進(jìn)度progress的數(shù)據(jù)來(lái)源于實(shí)際上由session task來(lái)驅(qū)動(dòng)
*/
[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];
}];
}
/*
觀察progress的fractionCompleted屬性
*/
[self.downloadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.uploadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
- (void)cleanUpProgressForTask:(NSURLSessionTask *)task {
[self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
[self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
else if ([object isEqual:self.uploadProgress]) {
if (self.uploadProgressBlock) {
self.uploadProgressBlock(object);
}
}
}
setupProgressForTask:這個(gè)方法代碼很長(zhǎng),但是內(nèi)容卻比較簡(jiǎn)單且好理解。簡(jiǎn)單說(shuō)就是將下載任務(wù)task的數(shù)據(jù)總量、上傳/下載進(jìn)度等信息賦值給代理類的uploadProgress或downloadProgress屬性。除此外,并且還實(shí)現(xiàn)了uploadProgress和downloadProgress倆屬性取消、暫停、重啟操作的block回調(diào),可以看到它倆這三個(gè)操作實(shí)際上是由對(duì)應(yīng)的task實(shí)現(xiàn)的。也就是說(shuō),代理類的進(jìn)度信息的數(shù)據(jù)既是task賦給的,其操作動(dòng)作也是task驅(qū)動(dòng)的。總之,把一切使用者感興趣的東西都從task抽離出去,置給了代理類。
還沒(méi)完,在這個(gè)方法結(jié)尾,給進(jìn)度的屬性fractionCompleted“完成度百分比”添加了監(jiān)聽(tīng),即KVO。只要下載百分比變化,就執(zhí)行下面監(jiān)聽(tīng)的代理方法,執(zhí)行self.downloadProgressBlock(object);,調(diào)用其block回調(diào)屬性。這里object便是所監(jiān)聽(tīng)的屬性的主人,即downloadProgress或uploadProgress。如此該代理類的uploadProgressBlock和downloadProgressBlock倆block回調(diào)屬性便擁有進(jìn)度數(shù)據(jù)了。想一下,該代理類不是有uploadProgress和downloadProgress屬性嗎?為什么還要多此一舉,去觀察該進(jìn)度的完成百分比,然后再將進(jìn)度賦值給進(jìn)度對(duì)應(yīng)的blockdownloadProgressBlock和uploadProgressBlock呢?這是因?yàn)槲覀冏罱K給使用者調(diào)用的接口方法是以該類型block回調(diào)的,在這里完成block的賦值,然后將回調(diào)回去回傳給使用層時(shí),直接賦值給同類型的block就行了。
最后來(lái)看session task、session dataTask和session downTask代理方法的實(shí)現(xiàn)。先看session task代理方法的實(shí)現(xiàn):
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
//Performance Improvement from #2672
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,則說(shuō)明文件下載在磁盤了,downloadFileURL為其路徑;反之,數(shù)據(jù)是存在data里的
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, error);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
} else {
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
if (self.downloadFileURL) {
responseObject = self.downloadFileURL;
}
if (responseObject) {
userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
}
if (serializationError) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
}
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
}
這個(gè)方法里代碼很長(zhǎng),但仔細(xì)看看,其實(shí)也不復(fù)雜。其實(shí)就是數(shù)據(jù)獲取完成了,想發(fā)送一個(gè)通知AFNetworkingTaskDidCompleteNotification,發(fā)送該通知時(shí)要攜帶一個(gè)NSDictionary型的參數(shù)信息userInfo,而前面的一大串代碼都是為了給該參數(shù)賦值。而發(fā)出的這個(gè)通知,主要用于通知框架里的UI層。
上面的代碼使我比較困惑的是?:符號(hào)的含義,x?:y == x?x:y。一開(kāi)始我以為這就是個(gè)普通的三元運(yùn)算符,表示無(wú)論x真假,都執(zhí)行y,這樣理解是錯(cuò)誤的,應(yīng)當(dāng)是若x成立,則執(zhí)行x,否則執(zhí)行y。
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);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
這段代碼里?:符號(hào)所表示的邏輯是:若存在自定義的任務(wù)完成時(shí)的block回調(diào)所在的completionGroup,則用自定義的;否則用一個(gè)方法生成一個(gè)專門的,用于完成任務(wù)時(shí)的block回調(diào)所在的group。同理,后半句表示若存在自定義的任務(wù)完成時(shí)的block回調(diào)所在的completionQueue,則用自定義的;否則用main queue。
這里的邏輯實(shí)際上在AFURLSessionManager頭文件里定義這倆屬性時(shí)便在注釋里已有說(shuō)明:
/**
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;
至此,我們把AFURLSessionManagerTaskDelegate代理類算是看完了,也清楚了它的作用就是把請(qǐng)求網(wǎng)絡(luò)所返回的數(shù)據(jù)信息或者錯(cuò)誤信息抽離至這個(gè)代理類中。現(xiàn)在數(shù)據(jù)我們看見(jiàn)是抽離在該類里了,但是它是怎么回傳給使用者的,我們最好再次梳理一下。
使用者是調(diào)用HTTP的便利方法來(lái)請(qǐng)求網(wǎng)絡(luò)獲取響應(yīng)數(shù)據(jù)的,而響應(yīng)的數(shù)據(jù)信息或錯(cuò)誤信息是通過(guò)downloadProgress、success、failure三個(gè)block回調(diào)的。
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
// 該方法的目的仍是生成dataTask實(shí)例,不過(guò)參數(shù)更豐富靈活。
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
...
...
這三個(gè)block回調(diào)的數(shù)據(jù)信息從哪里得來(lái)呢?我們跳進(jìn)方法里可以看到,它的block數(shù)據(jù)便從里面這個(gè)方法的block而來(lái)。
我們?cè)偬M(jìn)里面這個(gè)方法觀察??梢钥吹剿腷lock回調(diào)數(shù)據(jù)同樣來(lái)自一個(gè)內(nèi)部方法的block回調(diào):
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
...
...
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
...
...
我們繼續(xù),再跳進(jìn)這個(gè)方法觀察。它的block數(shù)據(jù)依舊來(lái)源于內(nèi)部一個(gè)方法的block回調(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 {
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
...
...
我們?cè)倮^續(xù),跳進(jìn)該方法,一切清晰了:該方法的block并沒(méi)有來(lái)自其他的方法回調(diào)了,而是來(lái)自本篇所講的代理類的。也就是說(shuō),是在這個(gè)方法里,請(qǐng)求任務(wù)對(duì)應(yīng)的響應(yīng)數(shù)據(jù)或錯(cuò)誤信息等開(kāi)始從代理類流出,一層一層,從內(nèi)至外的回傳給使用者調(diào)用的HTTP便利接口方法,回傳給使用者。
- (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)建一個(gè)AFURLSessionManagerTaskDelegate代理類的對(duì)象,并為幾個(gè)屬性賦值。然后調(diào)用setDelegate:forTask:將其和dataTask綁定
*/
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;
}
結(jié)尾
本篇繼續(xù)解釋了代理類存在的作用,并解釋了一些具體實(shí)現(xiàn),最后再次梳理了下響應(yīng)數(shù)據(jù)的流向。現(xiàn)在算是把AFURLSessionManagerTaskDelegate類說(shuō)完了。下篇學(xué)習(xí)學(xué)習(xí)序列化。