AFNetworking2.0源码解析<四>
结构
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 |
AFNetworking2.0源码解析<四>的更多相关文章
- AFNetworking2.0源码解析<一>
本篇先看看AFURLConnectionOperation,AFURLConnectionOperation继承自NSOperation,是一个封装好的任务单元,在这里构建了NSURLConnecti ...
- AFNetworking2.0源码解析<三>
本篇说说安全相关的AFSecurityPolicy模块,AFSecurityPolicy用于验证HTTPS请求的证书,先来看看HTTPS的原理和证书相关的几个问题. HTTPS HTTPS连接建立过程 ...
- AFNetworking2.0源码解析<二>
本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization. AFURLRequestSerialization用于帮助构建NSURLReque ...
- AFNetworking (3.1.0) 源码解析 <四>
这次主要看一下文件夹Security中的类AFSecurityPolicy----安全策略类. AFSecurityPolicy主要的作用是验证HTTPS请求证书的有效性,在iOS9之后,默认不能发送 ...
- solr&lucene3.6.0源码解析(四)
本文要描述的是solr的查询插件,该查询插件目的用于生成Lucene的查询Query,类似于查询条件表达式,与solr查询插件相关UML类图如下: 如果我们强行将上面的类图纳入某种设计模式语言的话,本 ...
- Sentinel源码解析四(流控策略和流控效果)
引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...
- solr&lucene3.6.0源码解析(三)
solr索引操作(包括新增 更新 删除 提交 合并等)相关UML图如下 从上面的类图我们可以发现,其中体现了工厂方法模式及责任链模式的运用 UpdateRequestProcessor相当于责任链模式 ...
- Heritrix 3.1.0 源码解析(三十七)
今天有兴趣重新看了一下heritrix3.1.0系统里面的线程池源码,heritrix系统没有采用java的cocurrency包里面的并发框架,而是采用了线程组ThreadGroup类来实现线程池的 ...
- Android事件总线(二)EventBus3.0源码解析
1.构造函数 当我们要调用EventBus的功能时,比如注册或者发送事件,总会调用EventBus.getDefault()来获取EventBus实例: public static EventBus ...
随机推荐
- Android学习笔记之数据的Sdcard存储方法及操作sdcard的工具类
FileService.java也就是操作sdcard的工具类: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ...
- 双重Iterator 报错!!!!
List list = new ArrayList(); list.add(new String[]{"0","s1","0038",&qu ...
- collection集合整体结构图
- 企业链表C语言实现
/* * LinkList.h * * Created on: 2019年7月20日 * Author: Administrator */ #ifndef SRC_LINKLIST_H_ #defin ...
- jquery.fileupload-image-editor.js 中actions.resizeImage
https://github.com/ChuckForkJS/jQuery-File-Upload/blob/master/js/jquery.fileupload-image-editor.js a ...
- bash脚本计算某程序的进程数
脚本里面有时候需要判断某个程序是否启动,以及有几个进程下面用nginx来做实例 显示所有的nignx进程 ps -ef|grep nginx |grep -v grep 其中grep -v grep表 ...
- reduce、map、zip、filter使用记录
注意:结果取完一次就没了: # -*- coding:utf-8 -*- ### functools.reduce from functools import reduce r1 = reduce(l ...
- leetcode-mid-others-150. Evaluate Reverse Polish Notation
mycode 42.30%. 注意:如果不考虑符号,-1//3=-1而不是等于0,因为是向下取整 class Solution(object): def evalRPN(self, tokens) ...
- MS入门学习笔记
1.建立晶体:选择晶系,添加原子:2.导入系统晶体文件:3.建立分子molecule,画原子:4.计算简单分子molecule:注意事项: 1)做了一个H2O分子,接下来要做一个“立体壳子”,因为CA ...
- oracle 日期格式操作
原文转自:http://hi.baidu.com/gzfvb/blog/item/5062b7f008eb70a8a50f5206.html Oracle日期格式: to_date(" ...