AFNetworking源码解析

Reading Notes-AFNetworking

OSA:Open Source Analyse
Version:3.1.0 release
Address:AFNwtworking GitHub

Core Class

AFHTTPSessionManager

这个类是AFURLSessionManager的子类。
封装了基本的HTTP请求操作。如POST、GET等。
有几个重要的Paramter:

baseUrl requestSerializer responseSerializer securityPolicy
服务器的域名 请求体的序列化数据 相应体的序列化数据 安全策略

-

AFURLSessionManager

AF框架最重要的类。
处理请求及网络队列、NSURLSession的Delegate、安全策略、断网重连等。
因为这个类是核心,所以就把每个Param都详细说一下吧。

session
-NSURLSession的实例,跟AFURLSessionManager同时实例化,网络操作的基础。


operationQueue
-NSOperationQueue的实例,跟AFURLSessionManager同时实例化。算是iOS中多线程最高层的封装。
-这个operationQueue是给session初始化用的。
-NSOperationQueue添加的任务默认是并发执行的。但是这里有一行代码:self.operationQueue.maxConcurrentOperationCount = 1;。把并发数设置为1,那session就是串行执行任务了。


responseSerializer
-看名字就知道是网络响应的序列化类。AFURLSessionManager一起实例化。在SessionTask完成网络请求后会对原始的网络Response进行一次组织序列化。


tasks/dataTasks/uploadTasks/downloadTasks
-获取不同种类的Task集合。
-这里作者用了NSStringFromSelector(_cmd)这种字符串化函数名的方法去获对比获取参数。这个偷懒方法不错。
-作者还用了一个异步block常用的等待回调方法。dispatch_semaphore_t/dispatch_semaphore_signal/dispatch_semaphore_wait。看了这里之后才发现非常好用。这里决定详细写一下用法。

- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
__block NSArray *tasks = nil;
//step0->这里创建了一个0的信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
        tasks = dataTasks;
    } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
        tasks = uploadTasks;
    } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
        tasks = downloadTasks;
    } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
        tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
    }
    //step2->完成,信号量+1。这时信号量=0。触发wait后面的代码。
    dispatch_semaphore_signal(semaphore);
}];
//step1->同步进入等待状态,信号量为-1。wait后面的代码等待执行。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//step3->信号量为0后执行这里。
return tasks;
}

-获取task总集合作者还有一个小技巧。tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
Google发现Mattt大神在其文章中有详解:KVC Collection Operators。是一种“Ruby-like–way”的方式去把数组集合合成一个array。
Stackoverflow的一个例子:How can I most easily flatten a three-dimensional array in Cocoa?


completionQueue/completionGroup
-这两个参数单纯就是在sessionTask的didComplete函数里处理error/success的回调,进行并行回调。并没有enter、leave、notify处理。可能以前有,现在去掉了吧。

-
下面是函数方法。

-

- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks
停止SessionTask。
cancelPendingTasks=ture时立即停止任务并cancel Task。调用invalidateAndCancel。
cancelPendingTasks=false时等待任务完成后停止Task。调用finishTasksAndInvalidate。


接下来有几个sessionTask创建方法。一般HTTP请求都被封装在AFHTTPSessionManager里面去了。大致都是带NSURLRequest入参。带Progress回调block。带completion回调这种。


sessionTask创建方法后会有几个对task请求体、响应体、回调block等的一些重设置。都是比较普通的方法。


最后定义了几个NSNotification的Key值。方便一对多的情况下监听回调。

-

AFNetworkReachabilityManager

非常方便的网络状态监听工具类。
实际上Apple官方也有一个Reachability
从头文件看AF的看起来会比较丰富好用一些。Apple官方的是没有block回调的。
具体方法不详细写了。看一些头文件都会怎么用。

-

AFSecurityPolicy

类名的意思是安全策略。
这个类的作用是对网络服务进行安全验证。主要是针对实现SSL协议的HTTPS。
从头文件的AFSSLPinningMode枚举看出有下面几种:


AFSSLPinningModeNone
这个模式是只从系统中的信任证书列表中验证通过。不做本地Cer证书验证。


AFSSLPinningModePublicKey
验证客户端本地的Cer证书。并把服务器的证书的公钥与本地证书公钥对比。受信证书count>0即通过。


AFSSLPinningModeCertificate
验证客户端本地的Cer证书。
Step0:把服务器证书与本地证书对比验证,验证的是kSecTrustResultUnspecified、kSecTrustResultProceed字段。从Sec​Trust​Evaluate官方文档中查阅,这两个值Apple是建议信任的。还有一个k​Sec​Trust​Result​Confirm值是旧版的macOS用到的。但现在已经基本废弃。
Step1:把服务器证书取出来,与本地证书进行内容对比。如果本地包含一个以上即通过。

-
还有两个重要的属性

-

allowInvalidCertificates
是否允许无效证书,默认NO。从代码来看只是对AFSSLPinningModeNone、AFSSLPinningModePublicKey有效。


validatesDomainName
是否验证域名,默认YES。

AFURLRequestSerialization

AF框架中对NSURLRequest的序列化封装。对HTTP协议的Header、Body、表单请求等进行了一些结构化的封装。这个类内容还挺多的,稍微详细写一下。

AFURLRequestSerialization
这是一个@protocol。实现这个协议的作用跟上面说的差不多。

- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                           withParameters:(nullable id)parameters
                                    error:(NSError * _Nullable __autoreleasing *)error

-这个协议只有这一个抽象函数。但这个函数是AFURLRequestSerialization的基础函数。其作用是拼装请求参数、编码Header/Body,并返回一个NSURLRequest实例。这个Request实例是在AFHTTPSessionManager中创建NSURLSessionDataTask用的。


stringEncoding
用来编码请求参数,默认是NSUTF8StringEncoding。


cachePolicy
请求的缓存策略,默认为NSURLRequestUseProtocolCachePolicy。


HTTPShouldHandleCookies
是否发送cookie。默认为YES。


HTTPShouldUsePipelining
是否使用请求管道化技术。默认为NO。这个需要跟服务器配合使用。当上一次请求未结束的时候,复用上次的请求通道。有点类似长连接。


networkServiceType
网络服务类型。默认为NSURLNetworkServiceTypeDefault。


timeoutInterval
请求超时时间


HTTPRequestHeaders
request的Header。


setAuthorizationHeaderFieldWithUsername:password:/clearAuthorizationHeader
HTTP header中的认证信息。会进行base64编码。存在即覆盖。


HTTPMethodsEncodingParametersInURI
相对重要的属性。一个NSString集合。包含HTTPMethod。默认为GET, HEAD, and DELETE。就是那些把参数放到URL中的请求方式。


setQueryStringSerializationWithStyle/setQueryStringSerializationWithBlock
实际上只有一个Style。但是这个set操作里面把block置为nil了,作用应该是这个。setQueryStringSerializationWithBlock的作用是自定义拼装URL中的query数据。即参数数据。


NSMutableURLRequest create
接下来几个都是NSMutableURLRequest创建函数,不详细写。


AFMultipartFormData
有几个函数可以把各种data新增到HTTP Body中去。方式有文件路径、输入流、NSData等。


AFJSONRequestSerializer/AFPropertyListRequestSerializer
AFHTTPRequestSerializer的子类。Header中的Content-Type有所不同。设为application/jsonapplication/x-plist。parameter的data化区分为NSJSONSerializationNSPropertyListSerialization。其他基本都一样。


最后是几个通知的key。一般比较少用。

-

AFURLResponseSerialization

这个类从头文件上看其实比较简单。看一下就知道用法,跟AFURLRequestSerialization有跟多类似之处。不准备详细写。只挑几个重要的东西。

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                       data:(nullable NSData *)data
                      error:(NSError * _Nullable __autoreleasing *)error

本类基本方法。对原始的response进行结构化封装。


acceptableStatusCodes
请求返回response中通过的code。默认为100、200。不包含在内的视为fail。


acceptableContentTypes
response的Content-Type。不包含在内的视为fail。


- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
                data:(nullable NSData *)data
               error:(NSError * _Nullable __autoreleasing *)error

判断response是否validate。一般就是判断前面写的两个属性值。


后面有几个子类是对acceptableContentTypes不同的设置。不详细写。


最后也是一如常态的给出了几个Constant Key。

-

End