结构

AFURLResponseSerialization负责解析网络返回数据,检查数据是否合法,把NSData数据转成相应的对象,内置的转换器有json,xml,plist,image,用户可以很方便地继承基类AFHTTPResponseSerializer去解析更多的数据格式,AFNetworking这一套响应解析机制结构很简单,主要就是两个方法:

1.-validateResponse:data:error:

基类AFHTTPResponseSerializer的这个方法检测返回的HTTP状态码和数据类型是否合法,属性acceptableStatusCodes和acceptableContentTypes规定了合法的状态码和数据类型,例如JSONSerialization就把acceptableContentTypes设为@”application/json”, @”text/json”, @”text/javascript”,若不是这三者之一,就验证失败,返回相应的NSError对象。一般子类不需要重写这个方法,只需要设置好acceptableStatusCodes和acceptableContentTypes就行了。

2.-responseObjectForResponse:data:error:

这个方法解析数据,把NSData转成相应的对象,上层AFURLConnectionOperation会调用这个方法获取转换后的对象。

在解析数据之前会先调上述的validateResponse方法检测HTTP响应是否合法,要注意的是即使这里检测返回不合法,也会继续解析数据生成对象,因为有可能错误信息就在返回的数据里。

如果validateResponse返回error,这里的解析数据又出错,这时有两个error对象,怎样返回给上层?这里的处理是把解析数据的NSError对象保存到validateResponse NSError的userInfo里,作为UnderlyingError,NSError专门给了个NSUnderlyingErrorKey作为这种错误包含错误的键值。

剩下的就是NSecureCoding相关方法了,如果子类增加了property,需要加上相应的NSecureCoding方法。

JSON解析

AFJSONResponseSerializer使用系统内置的NSJSONSerialization解析json,NSJSON只支持解析UTF8编码的数据(还有UTF-16LE之类的,都不常用),所以要先把返回的数据转成UTF8格式。这里会尝试用HTTP返回的编码类型和自己设置的stringEncoding去把数据解码转成字符串NSString,再把NSString用UTF8编码转成NSData,再用NSJSONSerialization解析成对象返回。

上述过程是NSData->NSString->NSData->NSObject,这里有个问题,如果你能确定服务端返回的是UTF8编码的json数据,那NSData->NSString->NSData这两步就是无意义的,而且这两步进行了两次编解码,很浪费性能,所以如果确定服务端返回utf8编码数据,就建议自己再写个JSONResponseSerializer,跳过这两个步骤。

此外AFJSONResponseSerializer专门写了个方法去除NSNull,直接把对象里值是NSNull的键去掉,还蛮贴心,若不去掉,上层很容易忽略了这个数据类型,判断了数据是否nil没判断是否NSNull,进行了错误的调用导致core。

图片解压

当我们调用UIImage的方法imageWithData:方法把数据转成UIImage对象后,其实这时UIImage对象还没准备好需要渲染到屏幕的数据,现在的网络图像PNG和JPG都是压缩格式,需要把它们解压转成bitmap后才能渲染到屏幕上,如果不做任何处理,当你把UIImage赋给UIImageView,在渲染之前底层会判断到UIImage对象未解压,没有bitmap数据,这时会在主线程对图片进行解压操作,再渲染到屏幕上。这个解压操作是比较耗时的,如果任由它在主线程做,可能会导致速度慢UI卡顿的问题。

AFImageResponseSerializer除了把返回数据解析成UIImage外,还会把图像数据解压,这个处理是在子线程(AFNetworking专用的一条线程,详见AFURLConnectionOperation),处理后上层使用返回的UIImage在主线程渲染时就不需要做解压这步操作,主线程减轻了负担,减少了UI卡顿问题。

具体实现上在AFInflatedImageFromResponseWithDataAtScale里,创建一个画布,把UIImage画在画布上,再把这个画布保存成UIImage返回给上层。只有JPG和PNG才会尝试去做解压操作,期间如果解压失败,或者遇到CMKY颜色格式的jpg,或者图像太大(解压后的bitmap太占内存,一个像素3-4字节,搞不好内存就爆掉了),就直接返回未解压的图像。

另外在代码里看到iOS才需要这样手动解压,MacOS上已经有封装好的对象NSBitmapImageRep可以做这个事。

关于图片解压,还有几个问题不清楚:

1.本来以为调用imageWithData方法只是持有了数据,没有做解压相关的事,后来看到调用堆栈发现已经做了一些解压操作,从调用名字看进行了huffman解码,不知还会继续做到解码jpg的哪一步。

2.以上图片手动解压方式都是在CPU进行的,如果不进行手动解压,把图片放进layer里,让底层自动做这个事,是会用GPU进行的解压的。不知用GPU解压与用CPU解压速度会差多少,如果GPU速度很快,就算是在主线程做解压,也变得可以接受了,就不需要手动解压这样的优化了,不过目前没找到方法检测GPU解压的速度。

P.S. 关于图片解压,有篇挺挺不错的文章:Avoiding Image Decompression Sickness

源码注释

1
AFURLResponseSerialization.m

最新文章

  1. 递推 hdu 3411
  2. LeetCode之263. Ugly Number
  3. 《Entity Framework 6 Recipes》中文翻译系列 (31) ------ 第六章 继承与建模高级应用之自引用关联
  4. 【转载】gcc 使用中常用的参数及命令
  5. 在getView方法产生给用户item的视图以及数据
  6. JAVA 内存管理总结
  7. 20、CSS
  8. MySQL flush tables with read lock
  9. easyui 表单验证validatetype——支持自定义验证
  10. ImageButton消除使用setImageDrawable造成的边框问题。
  11. 整合改造百度编译器到thinkphp上传图片到OSS
  12. PrefixSpan算法原理总结
  13. IntelliJ IDEA(六) :Settings(下)
  14. P1137 旅行计划
  15. 关于Ant脚本
  16. 《python语言程序设计》_第一章编程题
  17. JAVA虚拟机的生命周期
  18. ural 2032 Conspiracy Theory and Rebranding (数学水题)
  19. PostgreSQL 9.3:在windows(包括win7)下的安装与正确配置
  20. python遍历目录的方法 walk listdir

热门文章

  1. android 文件保存到应用和sd卡中
  2. centos网卡配置NM_CONTROLLED=”yes” 慎用
  3. c++结构体、共用体和枚举
  4. 【Spark机器学习速成宝典】基础篇03数据读取与保存(Python版)
  5. 算法中Amortised time的理解
  6. UNITY ET 框架
  7. hadoop stop-dfs.sh 无法停止 namenode datanode
  8. VS调试异常代码 HRESULT:0x80070057 (E_INVALIDARG)解决方法
  9. hibernate中get和load区别
  10. script标签defer与async的区别