本篇是 AFNetworking 源码解读的第三篇了。主要讲解接收到响应后的处理。
AFURLResponseSerialization 协议
AFURLResponseSerialization
协议只有一个方法需要实现:
1 | - (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response |
这个协议会拿到响应对象 NSURLResponse
,响应数据 NSData
。可以根据 NSURLResponse
返回数据类型标识 content-type
选取相应的解析器,来解析 data.
AFHTTPResponseSerializer 基类
AFHTTPResponseSerializer
是一个基类,提供最基本的属性和方法,针对不同 content-type
的响应报文,需要实例化不同的子类进行解析。
AFHTTPResponseSerializer
有两个重要的属性:
1 | /// 设置接收的状态码,不在此内的状态码返回错误 |
它们会在初始化方法中赋值:
1 | - (instancetype)init { |
因为 AFHTTPResponseSerializer
不做任何类型校验,因此其 acceptableContentTypes
为 nil,表示所有类型皆可,这个属性会在不同子类中设置为不同类型。
acceptableStatusCodes
是一个 NSIndexSet
实例,是一个有序的,唯一的,无符号整数的集合。比如:
1 | NSMutableIndexSet *indexSetM = [NSMutableIndexSet indexSet]; |
addIndexesInRange:
方法可以设定一个范围。因此上面的代码中 acceptableStatusCodes
代表的是只接受 200-299 的状态码。
根据上面的有效状态码和有效 content-type,基类中还有一个验证方法。如果验证无效,会抛出 NSError
:
1 | /// 验证服务器返回的数据,是否符合接收的状态码和 content-type |
AFJSONResponseSerializer
解析 JSON 的序列化类。它的 content-type
为 @"application/json", @"text/json", @"text/javascript"
1 | - (instancetype)init { |
序列化方法通过 NSJSONSerialization
将 NSData
转为 json 对象,一般是一个字典或者数组:
1 | - (id)responseObjectForResponse:(NSURLResponse *)response |
最后还会删除数据中值为 NSNull
的 key:
1 | /// 移除空的 key |
注意,数组中的空对象是不会被删除的,只会删除字典中的值为 nil 的键
AFXMLParserResponseSerializer
解析 xml 的序列化类。它的 content-type
为 @"application/xml", @"text/xml"
:
1 | - (instancetype)init { |
通过系统类 NSXMLParser
解析:
1 | - (id)responseObjectForResponse:(NSHTTPURLResponse *)response |
AFPropertyListResponseSerializer
解析 plist 的序列化类。它的 content-type 为 @"application/x-plist"
1 | - (instancetype)init { |
通过 NSPropertyListSerialization
解析:
1 | - (id)responseObjectForResponse:(NSURLResponse *)response |
AFImageResponseSerializer
解析 image 的序列化类。它的 content-type 为 @"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap"
。
它还有一个属性 automaticallyInflatesResponseImage
用来设置是否自动解码:
1 | - (instancetype)init { |
它的解析方式如下:
1 | - (id)responseObjectForResponse:(NSURLResponse *)response |
其中涉及到两个方法 AFInflatedImageFromResponseWithDataAtScale
和 AFImageWithDataAtScale
。先来看后者,它通过 NSData 创建 image:
1 | /// 创建 image |
上面创建图片的方式比较普通,不太能理解为什么要加锁。然后是 AFInflatedImageFromResponseWithDataAtScale
:
1 | /// 将png和jpeg图片解码 |
这个方法能解析 png 和 jpeg 图片,会将图片解码,这样能加速图片的显示速度。
AFCompoundResponseSerializer
复合类型的序列化器。在创建的时候需要传入上面的各种序列化方式的实例:
1 | + (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers { |
在获取到响应信息的时候会调用内部的各种序列化器尝试转换:
1 | - (id)responseObjectForResponse:(NSURLResponse *)response |
总结
总体来说,响应的序列化类不像请求那样涉及到输入流,因此还是比较清晰简单的。只要针对不同的 content-type
选取不同的系统类进行解析即可。
针对图片格式,AFNetworking 做了一部分图片解码转换的功能,但是和 SDWebImage 相比还是简单了很多。