天天看点

IOS应用架构思考二(网络图片库)

移动端架构中图片库是非常重要的一环,其实图片库也可以理解为网络库的一种特殊使用模式,为了满足需要,图片库至少要满足以下特点:

提供一个加载入口,通常以uiimageview的类别方法<code>setimagewithurl:...</code>开始

支持异步网络加载图片

支持内存缓存和文件缓存

确保同一张图片不会被重复下载

主流图片格式的解码

著名的优秀关于图片加载的库有:

<a href="https://github.com/rs/sdwebimage">sdwebimage</a>

<a href="https://github.com/afnetworking/afnetworking">afnetworking</a>

首先你要设计一个全局的队列来执行下载任务,因为我们要保证下载任务不重复,那么就需要一个任务管理器来统一调度下载任务,比如有2个uiimageview同时加载同一张图片,那么就只执行一次下载,下载完成回调给2个view就行了。

回调的方式 <code>sdwebimage</code> 采用<code>block</code>的方式,<code>egoimageloading</code>采用了<code>notification</code>的方式, 因为可能存在多个回调, 所以不太适合用delegate的方式进行回调,不过如果非要想用也可以,可以创建一个weak引用的<code>cfarrayref</code> 或者用 <code>nshashtable</code> 来把保存 delegate 指针。

说到缓存,我们知道在ios5之后,nsurlcache 也有diskcache了,是不是我们不需要自己实现cache机制了,直接使用nsurlcache就好了呢? 分析这个必要性,我们首先要思考nsurlcache中保存的是什么,nsurlcache中保存的是http协议返回的rawdata, 没有经过解压和解码的过程, 如果直接使用nsurlcache, 那么每次读缓存的时候就还需要把rawdata解码为我们需要的uiimage,这肯定会带来额外的cpu开销。那如果我们 自己来做缓存,我们可以将解码后的数据保存到disk,就可以减少我们读缓存的时间了。这一点也是我觉得sdwebimage唯一比afnetworking好 的一个亮点了,其他的afnetworking也都做到了,(afnetworking直接使用nsurlcache做diskcache, 在后台线程解码image)

关于缓存,我们还需要设计内存缓存,diskcache 在读取的时候还是要消耗i/o的时间,可能带来对fps的影响和电量的消耗, 那么我们设计内存缓存在一定程度上可以缓解这个问题,对于频繁使用的图片,效果会更好。ps: 内存缓存需要做好内存控制,不能让其过多 的占用内存,比如内存警告时要清空。 nsurlcache 虽然也有内存缓存,但是不太可控,所以内存缓存还是自己实现比较合适。

缓存时间的设定其实比较重要,其实有时候缓存时间的设置,使用nsurlcache的话,缓存时间可以是由图片服务器来决定的,客户端不用太操心什么, 这个是用nsurlcache的好处,那么如果我们自己实现的缓存方式呢,sdwebimage里面是可以统一设置缓存的时间,默认是一周的时间,其实这个设定 我是觉得不太合理的,因为不同的业务场景很可能会要求不同的缓存时间设定,怎么能够大一统的设置了事,不过好在现在的一般应用场景没有对缓存 时间硬性的要求,所以用起来也没什么问题。

话说我以前在苏宁易购的时候,就对egoimageloading做过大修改,添加了很多sdwebimage的优点特性,关于缓存时间也做了个性化设定。但其实nsurlcache 的方式才是决定缓存寿命的最好的方式。

有时候可能会有一些图片裁剪的需求,比如说placeholder随着view大小自适应,或者一张源图片可能会裁剪为不同尺寸来展示,那么这个时候可能会做一些裁剪的 操作,裁剪操作可能需要做到2点,不要在主线程做,不要重复裁剪相同尺寸。

暂时也写到这吧,以后有补充再写,欢迎勘误。