AFNURLConnectionOperation
AFNURLConnectionOperation
是AFNetworking之前框架中完成網絡請求的最主要的類, AFNURLConnectionOperation
繼承于NSOperation
,服從NSURLConnectionDelegate
,NSURLConnectionDataDelegate
, NSSecureCoding
,NSCopying
協議坞嘀。是一個封裝好的請求任務單元,有請求request
、響應response
午磁、加密證書securityPolicy
,下傳流inputStream
催跪、上傳流outputStream
扳肛、完成的OperationcompletionQueue
,完成的groupoperationGroup
等屬性。
AFURLSessionManager
在Xcode7之后, NSURLConnection
的API已經正式被蘋果遺棄,雖然還是可以使用,但是新功能不會再添加,不會對其再進行維護。所以是時候對NSURLSession
的API進行運用了颜阐。
棄用的類
下面的類已從AFNetworking 3.0中廢棄:
AFURLConnectionOperation
AFHTTPRequestOperation
AFHTTPRequestOperationManager
AFURLSessionManager
繼承NSObject
,服從NSURLSessionDelegate
, NSURLSessionTaskDelegate
, NSURLSessionDataDelegate
, NSURLSessionDownloadDelegate
, NSSecureCoding
, NSCopying
協議。是用來管理NSURLSession
的封裝單元吓肋。
AFURLSessionManager.m中包含三部分:
- AFURLSessionManagerTaskDelegate:用來管理網絡請求的信息,并且處理請求完成回調
- _AFURLSessionTaskSwizzling:用來完成resume與af_resume的swizzling的類
- AFURLSessionManager:主體控制網絡請求的相關功能
在AFURLSessionManager
中,創(chuàng)建時,創(chuàng)建一個NSOperationQueue
,最大operation數為1,規(guī)定請求delegate的Operation是唯一的凳怨。在這個類中,開辟了唯一的一個串行隊列url_session_manager_creation_queue
來調用NSURLSession
的請求方法,唯一的一個并行隊列url_session_manager_processing_queue
來進行進程,使用唯一的一個groupurl_session_manager_completion_group
來管理完成線程。
為保證線程安全,所以得單例都是使用dispatch_once生成
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;
}
并且通過kvo監(jiān)控resume情況
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:nil];
調用網絡請求的方法中,會創(chuàng)建一個NSURLSessionDataTask
對象,用來返回給用戶,在之前單例創(chuàng)建的線程中url_session_manager_creation_queue
調用init
中創(chuàng)建的session屬性來執(zhí)行請求方法是鬼。
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
__block NSURLSessionDataTask *dataTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
dataTask = [self.session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask completionHandler:completionHandler];
return dataTask;
由- (void)addDelegateForDataTask
可以看出來在框架中用于管理請求信息與數據的回調的是AFURLSessionManagerTaskDelegate
肤舞。
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
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];
}
AFURLSessionManagerTaskDelegate
和NSURLSessionTask
的關系是由AFURLSessionManager
管理的。addDelegateForDataTask
方法中除了創(chuàng)建AFURLSessionManagerTaskDelegate
類與配置其屬性以外,如果是上傳,會配置content-length
以及delegate.progress
的相關block屬性屑咳。如果是下載,則會配置完成download的block屬性
if (destination) {
delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
return destination(location, task.response);
};
}
if (progress) {
*progress = delegate.progress;
}
downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
之后的一個方法是setDelegate:forTask:
,它將AFURLSessionManagerTaskDelegate
與NSURLSessionDataTask
進行了綁定萨赁。方便之后對于請求數據的查找與回調。
mutableTaskDelegatesKeyedByTaskIdentifier
是將task的taskIdentifier與delegate綁定的重要屬性
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
我們想要得到包括進程等等屬性都在delegate里面可以得到兆龙。
在resume時需要外界能接收到一個didResume的消息,所以需要調用taskDidResume
方法杖爽。
- (void)taskDidResume:(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:AFNetworkingTaskDidResumeNotification object:task];
});
}
}
}
終于得到了AFNetworkingTaskDidResumeNotification
,有了它就方便多了,AFNetworkingTaskDidSuspendNotification
也是同理。
在這里其實還有一個很重要的知識點,AFNetworking對NSURLSessionTask
中的state進行了kvo處理,但是在iOS8上會導致莫名的crash,可能是由于iOS7與iOS8上的NSURLSessionTask是不同的,還好之后有大神通過swizzling解決了這個問題紫皇。在源碼中我們看到如果想要得到AFNetworkingTaskDidResumeNotification
通知,就要執(zhí)行- (void)taskDidResume:(NSNotification *)notification
方法,而這個方法是需要通過監(jiān)聽AFNSURLSessionTaskDidResumeNotification
通知來執(zhí)行的慰安。所以我們需要對resume方法進行修改,在resume方法中添加此通知,于是就通過swizzling在+ (void)load
中將af_resume與resume方法的imp進行交換。
af_resume方法實現
- (void)af_resume {
NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
NSURLSessionTaskState state = [self state];
[self af_resume];
if (state != NSURLSessionTaskStateRunning) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
}
}
對swizzling有興趣的可以看看這個源碼,這里就不延伸了,簡單來說就是將af_resume
的函數指針與resume
的函數指針進行調換,在調用resume
方法時其實調用的是af_resume
,調用af_resume
時則相反聪铺。
在網絡請求的過程中,AFURLSessionManager
在執(zhí)行相關的NSURLSessionDelegate
方法時,會調用這個請求相對應的AFURLSessionManagerTaskDelegate
類中的對應的NSURLSessionDelegate
方法,在AFURLSessionManagerTaskDelegate
中完成請求的信息展示和數據回調化焕。
AFURLSessionManager中的NSURLSessionDelegate回調
- (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);
}
}
在AFURLSessionManagerTaskDelegate
中的complete方法中則創(chuàng)建一個userInfo字典,儲存網絡請求的相關信息,然后通過消息中心postAFNetworkingTaskDidCompleteNotification
消息將userInfo傳出。其中,還在completionGroup
中調用主線程通過執(zhí)行completionHandler
將請求數據傳出铃剔。到此為止終于完成了一次完整的網絡請求撒桨。
AFURLSessionManagerTaskDelegate中的NSURLSessionDelegate回調
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
__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;
}
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];
});
});
});
}
#pragma clang diagnostic pop
}