AFNetworking源码<一>
来源:互联网 发布:fileinput.min.js 编辑:程序博客网 时间:2024/06/06 18:33
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
中,创建时,创建一个NSOperationQueue
,最大operation数为1,规定请求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监控resume情况
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:nil];
调用网络请求的方法中,会创建一个NSURLSessionDataTask
对象,用来返回给用户,在之前单例创建的线程中url_session_manager_creation_queue
调用init
中创建的session属性来执行请求方法。
- (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
方法中除了创建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
通知,就要执行- (void)taskDidResume:(NSNotification *)notification
方法,而这个方法是需要通过监听AFNSURLSessionTaskDidResumeNotification
通知来执行的。所以我们需要对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
在执行相关的NSURLSessionDelegate
方法时,会调用这个请求相对应的AFURLSessionManagerTaskDelegate
类中的对应的NSURLSessionDelegate
方法,在AFURLSessionManagerTaskDelegate
中完成请求的信息展示和数据回调。
AFURLSessionManager中的NSURLSessionDelegate回调
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(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方法中则创建一个userInfo字典,储存网络请求的相关信息,然后通过消息中心postAFNetworkingTaskDidCompleteNotification
消息将userInfo传出。其中,还在completionGroup
中调用主线程通过执行completionHandler
将请求数据传出。到此为止终于完成了一次完整的网络请求。
AFURLSessionManagerTaskDelegate中的NSURLSessionDelegate回调
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(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}
- AFNetworking源码<一>
- AFNetworking源码解析(一)
- AFNetworking源码解析(一)
- AFNetworking源码分析(一)
- 转载AFNetworking源码解析(一)
- iOS AFNetWorking源码详解(一)
- AFNetworking 3.0 源码阅读笔记(一)
- AFNetWorking(3.0)源码分析(一)——基本框架
- AFNetworking 的设计与实现 源码分享 (一)
- AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager
- AFNetWorking(3.0)源码分析(一)——基本框架
- AFNetworking源码解析<三>
- AFNetworking源码解析<三>
- AFNetworking源码解析<三>
- AFNetworking源码解析<四>
- AFNetworking源码解析<四>
- AFNetworking源码解析https
- AFNetworking源码解析<三>
- Oracle中的NUMBER、FLOAT
- Mapreduce部署与第三方依赖包管理【hadoop mapreduce第三方jar包maven管理瘦身版本和臃肿版本各取所需】
- C#多态之虚方法
- 三种编程命名规则(匈牙利法,小驼峰法,大驼峰法)
- Manage our assets(待续)
- AFNetworking源码<一>
- HDOJ 3625 Examining the Rooms(斯特林数—求n个点形成k个环的方案数)
- 关于Servlet的小问题
- iOS开发-视图控制器相关
- iOS获取设备IP地址
- Unity渲染路径比较
- Messenger/Handler and Binder (2): callback
- linux命令行运行matlab操作说明
- Installshield 打包安装程序时写入注册表,及运行bat文件