二、Serialization的AFURLRequestSerialization部分
AFHTTPRequestSerializer是序列化器,主要功能是对传入的参数进行序列化。
在前一篇分析过,
其主要是通过构造request来实现其功能的,这里也将从这个入口开始,分析requestSerializer是如何构造这个NSMutableURLRequest *request对象的。
在此之前先来看一下AFHTTPRequestSerializer的初始化方法:
表示返回一个默认配置的序列化器。
self.stringEncoding为编码方式,如果不做特别设置默认是UTF8。
self.mutableHTTPRequestHeaders为请求头构建的字典,self.requestHeaderModificationQueue为self.mutableHTTPRequestHeaders的操作队列。
可以看得出对请求头字典的操作都在self.requestHeaderModificationQueue这个并发队列中进行。在获取请求头字典或是获取其中一个值时,
都使用同步添加任务。
在插入或移除条目时,
都使用了dispatch_barrier_async异步栅栏添加任务。
[NSLocale preferredLanguages]获取当前使用语言,参见详情1,参见详情2
这块就是向请求头中插入Accept-Language字段。
插入User-Agent字段,主要包含一些设备信息。
通过KVO添加对属性的观察,继续深入这个AFHTTPRequestSerializerObservedKeyPaths()函数:
可以看出是对着五个属性添加了属性观察,以timeoutInterval为例:
需要手动实现属性的 setter 方法,在设置操作的前后分别调用 willChangeValueForKey: 和 didChangeValueForKey方法,这两个方法用于通知系统该 key 的属性值即将和已经变更了;
下面开始具体分析这个request的构造方法:
系统方法创建NSMutableURLRequest *mutableRequest,并赋值url和HTTPMethod。
存储观察属性的相关值。
下面重点分析这个方法:
将self.HTTPRequestHeaders的值赋给request,所以如果在发送请求时要设置或添加请求头信息,都可通过self.HTTPRequestHeaders来完成。
下面就是最重要一部分编码过程:
分析AFURLRequestSerialization的默认编码过程:
再继续深入AFQueryStringPairsFromDictionary(parameters)这个方法:
下面可知AFQueryStringPairsFromDictionary方法只接受NSDictionary*类型参数列表。
构造一个空的数组以供后面使用,构造一个排序器,看的出是针对排序集合元素的description属性进行排序。
下面就是NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value)这个函数的核心部分,以参数为字典为例:
先对dictionary的allKeys按之前构造的排序器排序[dictionary.allKeys sortedArrayUsingDescriptors:@[sortDescriptor]],然后对排完序的数组进行遍历for(id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[sortDescriptor]]) {,
在遍历过程中每一步中递归调用[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSStringstringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]。具体分析这个方法:nestedKey为dictionary每个条目的key值,nestedValue为每个条目的value值,可知在第一次调这个方法时
传入的key为nil,所以在递归调用这个方法时传入的key即为nestedKey,传入的value即为nestedValue,假设nestedValue不为字典、数组、集合对象,则走入
具体看一下AFQueryStringPair这个类及相关方法。
可知是一个参数条目的对象,pair表示是成对出现的field和value组成的对象,这也符合一般情况下的网络请求参数格式。然后再加入方法起始时构造的mutableQueryStringComponents的数组中,当传进来的参数列表遍历结束后,返回一个由AFQueryStringPair*类型对象组成的数组。
这里是以一个常见格式的字典类型参数为例,其他参数列表类型同样。
接着返回到
这个方法里边,可看出
在这里对上一步返回的AFQueryStringPair*类型对象数组进行遍历,每一个对象调用[pair URLEncodedStringValue]编码方法。
可看出编码的核心方法是NSString * AFPercentEscapedStringFromString(NSString *string)
这个方法前源码中有一段注释文档
可参考这里
具体分析:
构造一个字符集allowedCharacterSet,除去kAFCharactersGeneralDelimitersToEncode和kAFCharactersSubDelimitersToEncode包含的字符,allowedCharacterSet中为字符中允许的字符,否则要转译。
这块是对传入的参数string进行相关的UTF-8编码,
allowedCharacterSet表示在编码中可以保留的字符,否则要转译。
参看详情
现在返回到
可知[pair URLEncodedStringValue]是对每一个AFQueryStringPair*类型的pair对象进行编码,再回到这里
可知query = AFQueryStringFromParameters(parameters)方法便可得到相应的编码后的字符串,回到这里
继续往下走
之前不知道self.HTTPMethodsEncodingParametersInURI这是干啥的,到这里明白了,看看之前的代码
可看出,如果请求使用get方式则走到这里
设置mutableRequest的URL值。
如果请求方式为post,则走到这里
意思是如果请求头没设置Content-Type,默认是application/x-www-form-urlencoded表单提交,然后[mutableRequest setHTTPBody:[querydataUsingEncoding:self.stringEncoding]]设置post请求的body体。
最终返回mutableRequest。
最后返回到这个方法
一个NSMutableURLRequest *类型的request对象构造完成,可以提供给上篇文章的NSDataTask用以构造dataTask请求任务对象。
接下来简析一下AFURLRequestSerialization的整体面貌:
可看出这篇文章所着重分析的request对象构造方法是@protocol AFURLRequestSerialization协议的方法。从AFURLRequestSerialization.h头文件可看出框架实现的序列化器有三种
AFHTTPRequestSerializer是最基础的类型遵守了AFURLRequestSerialization协议,AFJSONRequestSerializer用于json提交时使用,AFPropertyListRequestSerializer用于application/x-plist提交时使用,它们都单独实现了- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(nullableid)parameters error:(NSError*_Nullable__autoreleasing*)error方法。本文主要分析的是AFHTTPRequestSerializer的实现方法,其他两种不再赘述。