SDWebImage原理
最近复习到三方框架SDWebImage,对其原理思路不是很清楚,所以查了查资料总结一下。
SDWebImage应用了iOS中的沙盒机制,通过利用苹果官方提供的缓存类NSCache来实现图片下载,图片缓存,下载进度监听,gif处理等功能。
首先简单说一下iOS中的沙盒机制(SandBox):
-
它是一种安全体制,它规定了应用程序只能在为该应用创建的文件夹内读取文件,不可以访问其他地方的内容。所有的非代码文件都保存在这个地方,比如图片,声音,属性列表和文本文件等。
-
每个应用程序都在自己的沙盒内
-
不能随意跨越自己的沙盒去访问别的应用程序沙盒内容
-
应用程序向外请求或接收数据局都需要经过权限认证
-
-
默认情况下,每个沙盒含有3个文件夹:Documents, Library 和 tmp。因为应用的沙盒机制,应用只能在几个目录下读写文件
-
Documents:苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录,如果保存了下载的数据,程序提交会被直接被拒绝
-
Library:存储程序的默认设置或其它状态信息;
-
Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除
Library/Preferences:偏好设置文件 -
tmp:提供一个即时创建临时文件的地方,在iPhone在重启时,会丢弃所有的tmp文件。
-
NSCache
NSCache是线程安全的,在多线程操作中,不需要对Cache加锁。NSCache的key只是对对象的strong引用,对象不需要实现NSCopying协议,NSCache也不会像NSDictionary一样复制对象。
-
NSCache在系统发出低内存通知时,回自动删减缓存。
-
NSCache可以设置数量限制,通过countLimit与totalCostLimit来限制cache的数量或者限制cost。当缓存的数量超过countLimit,或者cost之和超过totalCostLimit,NSCache会自动释放部分缓存。
那么SDWebImage的原理,加载流程到底是什么样的?
SDWebImage 加载图片的流程
(1)入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。
(2)进入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache 从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:.
(3)先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
(4)SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示图片。
(5)如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。
(6)根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。
(7)如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:。进而回调展示图片。
(8)如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo:。
(9)共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。
(10)图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
(11)connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。
(12)connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理。
(13)图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
(14)在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。
(15)imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
(16)通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。
(17)将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。
(18)SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
(19)SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
(20)SDWebImagePrefetcher 可以预先下载图片,方便后续使用
若有不足之处和错误,还需改进。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步