AFNetworking到底做了什么.docx
- 文档编号:5255041
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:38
- 大小:35.72KB
AFNetworking到底做了什么.docx
《AFNetworking到底做了什么.docx》由会员分享,可在线阅读,更多相关《AFNetworking到底做了什么.docx(38页珍藏版)》请在冰豆网上搜索。
AFNetworking到底做了什么
AFNetworking到底做了什么?
前言
作为一个iOS开发,也许你不知道NSUrlRequest、不知道NSUrlConnection、也不知道NSURLSession...(说不下去了...怎么会什么都不知道...)但是你一定知道AFNetworking。
大多数人习惯了只要是请求网络都用AF,但是你真的知道AF做了什么吗?
为什么我们不用原生的NSURLSession而选择AFNetworking?
本文将从源码的角度去分析AF的实际作用。
先从最新的AF3.x讲起吧:
首先,我们就一起分析一下该框架的组成。
将AF下载导入工程后,下面是其包结构,相对于2.x变得非常简单了:
1.jpg
AF代码结构图.png
除去SupportFiles,可以看到AF分为如下5个功能模块:
网络通信模块(AFURLSessionManager、AFHTTPSessionManger)
网络状态监听模块(Reachability)
网络通信安全策略模块(Security)
网络通信信息序列化/反序列化模块(Serialization)
对于iOSUIKit库的扩展(UIKit)
其核心当然是网络通信模块NSURLSessionManager。
大家都知道,AF3.x是基于NSURLSession来封装的。
所以这个类围绕着NSURLSession做了一系列的封装。
而其余的四个模块,均是为了配合网络通信或对已有UIKit的一个扩展工具包。
这五个模块所对应的类的结构关系图如下所示:
2.jpg
AF架构图.png
其中AFHTTPSessionManager是继承于NSURLSessionManager的,我们一般做网络请求都是用AFHTTPSessionManager,但是它本身是没有做实事的,只是把一些请求逻辑分发给父类AFURLSessionManager或者其它类去做。
首先我们简单的写个get请求:
[js]viewplaincopyprint?
AFHTTPSessionManager*manager=[[AFHTTPSessionManageralloc]init];
[managerGET:
@"http:
//localhost"parameters:
nilprogress:
nilsuccess:
^(NSURLSessionDataTask*_Nonnulltask,id_NullableresponseObject){
}failure:
^(NSURLSessionDataTask*_Nullabletask,NSError*_Nonnullerror){
}];
首先我们我们调用了初始化方法生成了一个manager,我们点进去看看初始化做了什么:
[js]viewplaincopyprint?
-(instancetype)init{
return[selfinitWithBaseURL:
nil];
}
-(instancetype)initWithBaseURL:
(NSURL*)url{
return[selfinitWithBaseURL:
urlsessionConfiguration:
nil];
}
-(instancetype)initWithSessionConfiguration:
(NSURLSessionConfiguration*)configuration{
return[selfinitWithBaseURL:
nilsessionConfiguration:
configuration];
}
-(instancetype)initWithBaseURL:
(NSURL*)url
sessionConfiguration:
(NSURLSessionConfiguration*)configuration
{
self=[superinitWithSessionConfiguration:
configuration];
if(!
self){
returnnil;
}
//对传过来的BaseUrl进行处理,截去url最后的/
if([[urlpath]length]>0&&!
[[urlabsoluteString]hasSuffix:
@"/"]){
url=[urlURLByAppendingPathComponent:
@""];
}
self.baseURL=url;
self.requestSerializer=[AFHTTPRequestSerializerserializer];
self.responseSerializer=[AFJSONResponseSerializerserializer];
returnself;
}
初始化都调用到-(instancetype)initWithBaseURL:
(NSURL*)urlsessionConfiguration:
(NSURLSessionConfiguration*)configuration方法中来了。
其实初始化方法都调用父类的初始化方法。
父类也就是AF3.x最最核心的类AFHTTPSessionManager。
几乎所有的类都是围绕着这个类在处理业务逻辑。
除此之外,方法中把baseURL存了起来,还生成了一个请求序列对象和一个响应序列对象。
后面再细说这两个类是干什么用的。
直接来到父类AFURLSessionManager的初始化方法:
[js]viewplaincopyprint?
-(instancetype)init{
return[selfinitWithSessionConfiguration:
nil];
}
-(instancetype)initWithSessionConfiguration:
(NSURLSessionConfiguration*)configuration{
self=[superinit];
if(!
self){
returnnil;
}
if(!
configuration){
configuration=[NSURLSessionConfigurationdefaultSessionConfiguration];
}
self.sessionConfiguration=configuration;
self.operationQueue=[[NSOperationQueuealloc]init];
//queue并发线程数设置为1
self.operationQueue.maxConcurrentOperationCount=1;
//注意代理,代理的继承,实际上NSURLSession去判断了,你实现了哪个方法会去调用,包括子代理的方法!
self.session=[NSURLSessionsessionWithConfiguration:
self.sessionConfigurationdelegate:
selfdelegateQueue:
self.operationQueue];
//各种响应转码
self.responseSerializer=[AFJSONResponseSerializerserializer];
//设置默认安全策略
self.securityPolicy=[AFSecurityPolicydefaultPolicy];
#if!
TARGET_OS_WATCH
self.reachabilityManager=[AFNetworkReachabilityManagersharedManager];
#endif
//设置存储NSURLtask与AFURLSessionManagerTaskDelegate的词典(重点,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate来做task的delegate事件处理)===============
self.mutableTaskDelegatesKeyedByTaskIdentifier=[[NSMutableDictionaryalloc]init];
//设置AFURLSessionManagerTaskDelegate词典的锁,确保词典在多线程访问时的线程安全
self.lock=[[NSLockalloc]init];
self.lock.name=AFURLSessionManagerLockName;
//置空task关联的代理
[self.sessiongetTasksWithCompletionHandler:
^(NSArray*dataTasks,NSArray*uploadTasks,NSArray*downloadTasks){
for(NSURLSessionDataTask*taskindataTasks){
[selfaddDelegateForDataTask:
taskuploadProgress:
nildownloadProgress:
nilcompletionHandler:
nil];
}
for(NSURLSessionUploadTask*uploadTaskinuploadTasks){
[selfaddDelegateForUploadTask:
uploadTaskprogress:
nilcompletionHandler:
nil];
}
for(NSURLSessionDownloadTask*downloadTaskindownloadTasks){
[selfaddDelegateForDownloadTask:
downloadTaskprogress:
nildestination:
nilcompletionHandler:
nil];
}
}];
returnself;
}
这个就是最终的初始化方法了,注释应该写的很清楚,唯一需要说的就是三点:
self.operationQueue.maxConcurrentOperationCount=1;这个operationQueue就是我们代理回调的queue。
这里把代理回调的线程并发数设置为1了。
至于这里为什么要这么做,我们先留一个坑,等我们讲完AF2.x之后再来分析这一块。
第二就是我们初始化了一些属性,其中包括self.mutableTaskDelegatesKeyedByTaskIdentifier,这个是用来让每一个请求task和我们自定义的AF代理来建立映射用的,其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理,这是AF比较重要的一部分,接下来我们会具体讲这一块。
第三就是下面这个方法:
[self.sessiongetTasksWithCompletionHandler:
^(NSArray*dataTasks,NSArray*uploadTasks,NSArray*downloadTasks){
}];
首先说说这个方法是干什么用的:
这个方法用来异步的获取当前session的所有未完成的task。
其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有。
我们打断点去看,也确实如此,里面的数组都是空的。
但是想想也知道,AF大神不会把一段没用的代码放在这吧。
所以我大胆猜测,可能是当我们重复去初始化session的时候(当然我们实际也不会这么做),会有新的session指向旧的有未完成task的session。
为了排除这种不确定性因素,所以在初始化的时候把里面绑定的代理之类的东西都置为nil了。
或许这就是防御性编程思想的一种体现吧。
初始化方法到这就全部完成了。
3.jpg
分割图.png
接着我们来看看网络请求:
[js]viewplaincopyprint?
-(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
{
//生成一个task
NSURLSessionDataTask*dataTask=[selfdataTaskWithHTTPMethod:
@"GET"
URLString:
URLString
parameters:
parameters
uploadProgress:
nil
downloadProgress:
downloadProgress
success:
success
failure:
failure];
//开始网络请求
[dataTaskresume];
returndataTask;
}
方法走到类AFHTTPSessionManager中来,调用父类,也就是我们整个AF3.x的核心类AFURLSessionManager的方法,生成了一个系统的NSURLSessionDataTask实例,并且开始网络请求。
我们继续往父类里看,看看这个方法到底做了什么:
[js]viewplaincopyprint?
-(NSURLSessionDataTask*)dataTaskWithHTTPMethod:
(NSString*)method
URLString:
(NSString*)URLString
parameters:
(id)parameters
uploadProgress:
(nullablevoid(^)(NSProgress*uploadProgress))uploadProgress
downloadProgress:
(nullablevoid(^)(NSProgress*downloadProgress))downloadProgress
success:
(void(^)(NSURLSessionDataTask*,id))success
failure:
(void(^)(NSURLSessionDataTask*,NSError*))failure
{
NSError*serializationError=nil;
//把参数,还有各种东西转化为一个request
NSMutableURLRequest*request=[self.requestSerializerrequestWithMethod:
methodURLString:
[[NSURLURLWithString:
URLStringrelativeToURL:
self.baseURL]absoluteString]parameters:
parameterserror:
&serializationError];
if(serializationError){
if(failure){
#pragmaclangdiagnosticpush
#pragmaclangdiagnosticignored"-Wgnu"
//如果解析错误,直接返回
dispatch_async(pletionQueue?
:
dispatch_get_main_queue(),^{
failure(nil,serializationError);
});
#pragmaclangdiagnosticpop
}
returnnil;
}
__blockNSURLSessionDataTask*dataTask=nil;
dataTask=[selfdataTaskWithRequest:
request
uploadProgress:
uploadProgress
downloadProgress:
downloadProgress
completionHandler:
^(NSURLResponse*__unusedresponse,idresponseObject,NSError*error){
if(error){
if(failure){
failure(dataTask,error);
}
}else{
if(success){
success(dataTask,responseObject);
}
}
}];
returndataTask;
}
这个方法做了两件事:
1.用self.requestSerializer和各种参数去获取了一个我们最终请求网络需要的NSMutableURLRequest实例。
2.调用另外一个方法dataTaskWithRequest去拿到我们最终需要的NSURLSessionDataTask实例,并且在完成的回调里,调用我们传过来的成功和失败的回调。
注意下面这个方法,我们常用来pushpop搭配,来忽略一些编译器的警告:
[js]viewplaincopyprint?
#pragmaclangdiagnosticpush
#pragmaclangdiagnosticignored"-Wgnu"
#pragmaclangdiagnosticpop
这里是用来忽略:
?
带来的警告,具体的各种编译器警告描述,可以参考这篇:
各种编译器的警告。
说到底这个方法还是没有做实事,我们继续到requestSerializer方法里去看,看看AF到底如何拼接成我们需要的request的:
接着我们跑到AFURLRequestSerialization类中:
[js]viewplaincopyprint?
-(NSMutableURLRequest*)requestWithMethod:
(NSString*)method
URLString:
(NSString*)URLString
parameters:
(id)parameters
error:
(NSError*__autoreleasing*)error
{
//断言,debug模式下,如果缺少改参数,crash
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL*url=[NSURLURLWithString:
URLString];
NSParameterAssert(url);
NSMutableURLRequest*mutableRequest=[[NSMutableURLRequestalloc]initWithURL:
url];
mutableRequest.HTTPMethod=method;
//将request的各种属性循环遍历
for(NSString*keyPathinAFHTTPRequestSerializerObservedKeyPaths()){
//如果自己观察到的发生变化的属性,在这些方法里
if([self.mutableObservedChangedKeyPathscontainsObject:
keyPath]){
//把给自己设置的属性给request设置
[mutableRequestsetValue:
[selfvalueForKeyPath:
keyPath]forKey:
keyPath];
}
}
//将传入的parameters进行编码,并添加到request中
mutableRequest=[[selfrequestBySerializingRequest:
mutableRequestwithParameters:
parameterserror:
error]mutableCopy];
returnmutableRequest;
}
讲一下这个方法,这个方法做了3件事:
1)设置request的请求类型,get,post,put...等
2)往request里添加一些参数设置,其中AFHTTPRequestSerializerObservedKeyPaths()是一个c函数,返回一个数组,我们来看看这个函数:
[js]viewplaincopyprint?
staticNSArray*AFHTTPRequestSerializerObservedKeyPaths(){
staticNSArray*_AFHTTPRequestSerializerObservedKeyPaths=nil;
staticdispatch_once_tonceToken;
//此处需要observer的keypath为allowsCellularAccess、cachePolicy、HTTPShouldHandleCookies
//HTTPShouldUsePipelining、networkServiceType、timeoutInterval
dispatch_once(&onceToken,^{
_AFHTTPRequestSerializerObservedKeyPaths=@[NSStringFromSelector(@selector(allowsCellularAccess)),NSStringFromSelector(@selector(cachePolicy)),NSStringFromSelector(@selector(HTTPShouldHandleCookies)),NSStringFromSelector(@selector(HTTPShouldUsePipelining)),NSStringFromSelector(@selector(networkServiceType)),NSStringFromSelector(@selector(timeoutInterval))];
});
//就是一个数组里装了很多方法的名字,
return_AFHTTPRequestSerializerO
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AFNetworking 到底 什么