结构

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源码解析<四>的更多相关文章

  1. AFNetworking2.0源码解析<一>

    本篇先看看AFURLConnectionOperation,AFURLConnectionOperation继承自NSOperation,是一个封装好的任务单元,在这里构建了NSURLConnecti ...

  2. AFNetworking2.0源码解析<三>

    本篇说说安全相关的AFSecurityPolicy模块,AFSecurityPolicy用于验证HTTPS请求的证书,先来看看HTTPS的原理和证书相关的几个问题. HTTPS HTTPS连接建立过程 ...

  3. AFNetworking2.0源码解析<二>

    本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization.   AFURLRequestSerialization用于帮助构建NSURLReque ...

  4. AFNetworking (3.1.0) 源码解析 <四>

    这次主要看一下文件夹Security中的类AFSecurityPolicy----安全策略类. AFSecurityPolicy主要的作用是验证HTTPS请求证书的有效性,在iOS9之后,默认不能发送 ...

  5. solr&lucene3.6.0源码解析(四)

    本文要描述的是solr的查询插件,该查询插件目的用于生成Lucene的查询Query,类似于查询条件表达式,与solr查询插件相关UML类图如下: 如果我们强行将上面的类图纳入某种设计模式语言的话,本 ...

  6. Sentinel源码解析四(流控策略和流控效果)

    引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...

  7. solr&lucene3.6.0源码解析(三)

    solr索引操作(包括新增 更新 删除 提交 合并等)相关UML图如下 从上面的类图我们可以发现,其中体现了工厂方法模式及责任链模式的运用 UpdateRequestProcessor相当于责任链模式 ...

  8. Heritrix 3.1.0 源码解析(三十七)

    今天有兴趣重新看了一下heritrix3.1.0系统里面的线程池源码,heritrix系统没有采用java的cocurrency包里面的并发框架,而是采用了线程组ThreadGroup类来实现线程池的 ...

  9. Android事件总线(二)EventBus3.0源码解析

    1.构造函数 当我们要调用EventBus的功能时,比如注册或者发送事件,总会调用EventBus.getDefault()来获取EventBus实例: public static EventBus ...

随机推荐

  1. logstash之OutPut插件

    output插件是经过了input,然后过滤结构化数据之后,接下来我们需要借助output传到我们想传到的地方.output相当于一个输出管道. 2.3.1: 将采集数据标准输出到控制台 配置示例: ...

  2. hdu5988(费用流,对数相乘做加法)

    题意:一个网络流的图,有n个点,从1~n,然后m条边,每个点有两个值,一个是人的数量si一个是饭的数量bi.每条m边有容量ci,还有走上去可能踩断电线的概率pi(第一次踩上去没有事,之后都要p概率). ...

  3. iOS应用将强制使用HTTPS安全加密-afn配置https(190926更新)

    WWDC 2016苹果开发者大会上,苹果在讲解全新的iOS10中提到了数据安全这一方面,并且苹果宣布iOS应用将从2017年1月起启用名为App Transport Security的安全传输功能. ...

  4. node初始化配置no

    原文链接:https://blog.csdn.net/jianleking/article/details/79130667 引言: 很久没有在windows上配过node, 记得以前node环境变量 ...

  5. fiddler之模拟请求超时和弱网模式

    在针对手机端测试时,很多情况下我们需要测试响应超时和弱网情况的响应情况.此时可以使用fiddler提供的断点和弱网功能进行测试. 1.请求超时 设置断点,是请求响应超时.查看请求结果. Rules-- ...

  6. VMware克隆虚拟机后mac地址重新设置

    ifconfig eth1   确定新网卡的MAC地址. nmcli con 确定新网卡的UUID vim /etc/udev/rules.d/70-persistent-net.rules 把原et ...

  7. 应用安全 - 无文件式攻击 - 潜伏型攻击 - WMI - 汇总

    wbemtest.exe Windows XP Windows 10

  8. Android - Android 面试题集

    1.Java部分 1.1 操作系统相关 1.什么是操作系统? 2.什么是线程,什么是进程? 1.2 JDK&JVM&JRE 1.JDK & JVM & JRE分别是什么 ...

  9. 简述在Vue脚手架中,组件以及父子组件(非父子组件)之间的传值

    1.组件的定义 组成: template:包裹HTML模板片段(反映了数据与最终呈现给用户视图之间的映射关系) 只支持单个template标签: 支持lang配置多种模板语法: script:配置Vu ...

  10. input函数以及while处理列表和字典

    一.函数input()的工作原理 .input()函数:获取输入的字符串 示例: message = input('请输入信息,方便电脑显示') print(message) print('您输入的信 ...