AFNetworking到底做了什么.docx

上传人:b****6 文档编号:5255041 上传时间:2022-12-14 格式:DOCX 页数:38 大小:35.72KB
下载 相关 举报
AFNetworking到底做了什么.docx_第1页
第1页 / 共38页
AFNetworking到底做了什么.docx_第2页
第2页 / 共38页
AFNetworking到底做了什么.docx_第3页
第3页 / 共38页
AFNetworking到底做了什么.docx_第4页
第4页 / 共38页
AFNetworking到底做了什么.docx_第5页
第5页 / 共38页
点击查看更多>>
下载资源
资源描述

AFNetworking到底做了什么.docx

《AFNetworking到底做了什么.docx》由会员分享,可在线阅读,更多相关《AFNetworking到底做了什么.docx(38页珍藏版)》请在冰豆网上搜索。

AFNetworking到底做了什么.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 艺术

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1