AFURLSessionManager
這個類是AFNetworking最核心的類锰镀,它的任務就是管理會話,響應會話中的每一個任務
我們首先來梳理一下一次完整的網(wǎng)絡(luò)請求及其響應,看看它是走哪些方法,按照什么順序來走,我們就看一次最簡單的GET請求
首先显设,我們還記得在最外層AFHTTPSessionManager類中發(fā)起了請求任務
__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);
}
}
}];
它調(diào)用了它的父類也就是AFURLSessionManager的任務創(chuàng)建方法
- (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 {
//根據(jù)請求創(chuàng)建一個任務
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
//把創(chuàng)建的每一個任務交給一個AFURLSessionManagerTaskDelegate類來管理
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
addDelegateForDataTask
方法為每一個任務創(chuàng)建一個任務代理類,由它來全權(quán)獨立管理每個任務的狀態(tài)辛辨,進度和完成的回調(diào)捕捂,并且把它和每個任務進行一一對應,以便在會話中能正確響應每個任務的代理回調(diào)方法
這段代碼我認為也是最能表現(xiàn)AFNetworking這個框架精髓的一段代碼斗搞,它體現(xiàn)了AFNetworking的核心思想指攒,公用session,沒有必要進行多余的TCP連接僻焚,在一個會話里面創(chuàng)建多個任務允悦,獨立管理每個任務,這樣既能節(jié)約資源也能很大程度縮短網(wǎng)絡(luò)請求的時間虑啤,提高會話任務的效率
- (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
{
//根據(jù)任務來創(chuàng)建一個任務代理類
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
//將會話管理類也傳給任務代理類隙弛,以便使用會話管理中的方法
delegate.manager = self;
//完成任務的代碼塊也要傳給它
delegate.completionHandler = completionHandler;
//任務描述
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
//將每一個任務和它對應的任務管理類進行鍵值對關(guān)系綁定
[self setDelegate:delegate forTask:dataTask];
//上傳進度代碼塊
delegate.uploadProgressBlock = uploadProgressBlock;
//下載進度代碼塊
delegate.downloadProgressBlock = downloadProgressBlock;
}
這里就是為任務和任務代理類關(guān)系進行綁定的方法,以任務的ID為鍵狞山,AFURLSessionManagerTaskDelegate
對象為值全闷,這里還用了鎖,來保證綁定過程的安全
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
//這里用鎖來保證線程安全萍启,mutableTaskDelegatesKeyedByTaskIdentifier經(jīng)常需要被改動
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
發(fā)起請求后首先會進行https認證总珠,前面說的安全策略類AFSecurityPolicy就是在這里進行認證
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
BOOL evaluateServerTrust = NO;
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
NSURLCredential *credential = nil;
if (self.authenticationChallengeHandler) {
id result = self.authenticationChallengeHandler(session, task, challenge, completionHandler);
if (result == nil) {
return;
} else if ([result isKindOfClass:NSError.class]) {
objc_setAssociatedObject(task, AuthenticationChallengeErrorKey, result, OBJC_ASSOCIATION_RETAIN);
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
} else if ([result isKindOfClass:NSURLCredential.class]) {
credential = result;
disposition = NSURLSessionAuthChallengeUseCredential;
} else if ([result isKindOfClass:NSNumber.class]) {
disposition = [result integerValue];
NSAssert(disposition == NSURLSessionAuthChallengePerformDefaultHandling || disposition == NSURLSessionAuthChallengeCancelAuthenticationChallenge || disposition == NSURLSessionAuthChallengeRejectProtectionSpace, @"");
evaluateServerTrust = disposition == NSURLSessionAuthChallengePerformDefaultHandling && [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
} else {
@throw [NSException exceptionWithName:@"Invalid Return Value" reason:@"The return value from the authentication challenge handler must be nil, an NSError, an NSURLCredential or an NSNumber." userInfo:nil];
}
} else {
evaluateServerTrust = [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
if (evaluateServerTrust) {
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
disposition = NSURLSessionAuthChallengeUseCredential;
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
} else {
objc_setAssociatedObject(task, AuthenticationChallengeErrorKey,
[self serverTrustErrorForServerTrust:challenge.protectionSpace.serverTrust url:task.currentRequest.URL],
OBJC_ASSOCIATION_RETAIN);
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
}
if (completionHandler) {
completionHandler(disposition, credential);
}
}
服務器收到請求后返回數(shù)據(jù)屏鳍,這時候會響應NSURLSessionDataDelegate
接收返回數(shù)據(jù)的方法,這里數(shù)據(jù)可能是分多次返回局服,可能會響應多次
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
//根據(jù)任務找到對應的任務代理類
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
//調(diào)用代理類的數(shù)據(jù)接收方法钓瞭,和NSURLSessionDataDelegate的代理方法一致,只是在delegate里拼接可能多次返回的數(shù)據(jù)
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
//收到服務器返回數(shù)據(jù)回調(diào)的代碼塊
if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}
AFURLSessionManagerTaskDelegate
中的- (void)URLSession:dataTask:didReceiveData:
方法
- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
//下載進度設(shè)置
self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;
//拼接數(shù)據(jù)
[self.mutableData appendData:data];
}
接收服務器數(shù)據(jù)完成后腌逢,接著會響應NSURLSessionDataDelegate
中的- (void)URLSession:task:didCompleteWithError:
方法
- (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);
}
}
再繼續(xù)調(diào)用delegate中的該方法降淮,請求服務器數(shù)據(jù)完成回調(diào)
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
//如果有認證質(zhì)詢錯誤也要返回
error = objc_getAssociatedObject(task, AuthenticationChallengeErrorKey) ?: error;
//強引用超埋,防止被提前釋放
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
//創(chuàng)建一個信息字典
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
//存儲響應數(shù)據(jù)序列化信息
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.
//這時mutableData已經(jīng)沒有用搏讶,清空
self.mutableData = nil;
}
#if AF_CAN_USE_AT_AVAILABLE && AF_CAN_INCLUDE_SESSION_TASK_METRICS
if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, *)) {
//任務度量(包含請求響應時間等度量)
if (self.sessionTaskMetrics) {
userInfo[AFNetworkingTaskDidCompleteSessionTaskMetrics] = self.sessionTaskMetrics;
}
}
#endif
//下載數(shù)據(jù)存儲的位置
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);
}
//發(fā)送一條包含信息字典的通知
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;
}
//返回數(shù)據(jù)保存到信息字典
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) {
//網(wǎng)絡(luò)請求完成代碼塊
self.completionHandler(task.response, responseObject, serializationError);
}
//異步發(fā)送通知霍殴,帶有信息字典
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
}