在详细了解SDWebImage的时候,我们需要先了解以下几个关键词
1.什么是NSCache
:
-
NSCache
是苹果官方提供的缓存类,它的用法与NSMutableDictionary
的用法很相似,在AFNetworking及其SDWebImage中被使用来管理缓存。
2.苹果官方解释NSCache
在系统内存很低的时候会自动释放对象来删减缓存,建议接收到内存警告时主动调用removeAllObjects
方法释放对象。
3.NSCache
是线程安全的,在多线程操作中,不需要对NSCache
加锁。
4.NSCache
只是对Key进行Strong引用,不是拷贝。
5.缓存成本和缓存文件数
-
totalCostLimit:
缓存成本是一个单位的概念, 设置一个最大的缓存成本, 保存文件的时候为保存的文件设置单个缓存成本, 如果总成本超过最大的缓存成本, 就会自动释放旧的文件。
-
countLimit:
缓存文件可以设置NSCache对象缓存多少个文件, 如果超过最大值, 就会自动释放之前保存的。
NSCache * cache = [[NSCache alloc]init];
cache.countLimit = 10; //最大缓存数据的数量,如果超过该限制那么内部会自动开启一个回收过程把最先存储的数据删除
cache.totalCostLimit = 8;//设置最大的缓存成本(量),成本:单位概念
for(int i=0;i<10;i++){
//cost 成本,此情况下,虽然最大数是10,但是每次存储一个成本量就是1,所以最多能存8个,如果不设置cost,则最多10个
[cache setObject:@"数据" forKey:@(i) cost:1];
}
SDWebImage的大致工作流程:
- 入口
setImageWithURL:placeholderImage:options:
会先把placeholderImage
(占位图)显示,然后 SDWebImageManager
根据URL开始处理图片。
- 进入
SDWebImageManager-downloadWithURL:delegate:options:userInfo:
,交给 SDImageCache
从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:
。
- 先从内存
NSCache
图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate
回调imageCache:didFindImage:forKey:userInfo:
到 SDWebImageManager
。
-
SDWebImageManagerDelegate
回调 webImageManager:didFinishWithImage:
到 UIImageView+WebCache
等前端展示图片。
- 如果内存缓存中没有,生成
NSInvocationOperation
添加到队列开始从磁盘查找图片是否已经缓存(磁盘中的存储是根据图片后段路径进行MD5来作为key存储的,存储位置为沙盒下Library文件夹下Caches文件夹的default下)。
- 根据URL的Key在硬盘缓存目录下尝试读取图片文件。这一步是在
NSOperation
进行的操作,所以回主线程进行结果回调notifyDelegate:
。
- 如果上一操作从磁盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。
- 如果从磁盘缓存目录读取不到图片,说明所有缓存都不存在该图片则需要下载图片,回调
imageCache:didNotFindImageForKey:userInfo:
。
- 下载器
SDWebImageDownloader
开始下载图片。
- 图片下载由
NSURLConnection
来做,实现相关 delegate
来判断图片下载中、下载完成和下载失败。
-
connection:didReceiveData:
中利用ImageIO
做了按图片下载进度加载效果。
-
connectionDidFinishLoading:
数据下载完成后交给SDWebImageDecoder
做图片解码处理。
- 图片解码处理在一个
NSOperationQueue
完成,不会拖慢主线程UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
- 在主线程
notifyDelegateOnMainThreadWithInfo:
宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo:
回调给SDWebImageDownloader
。
-
imageDownloader:didFinishWithImage:
回调给 SDWebImageManager
告知图片下载完成。
- 通知所有的
downloadDelegates
下载完成,回调给需要的地方展示图片。
- 将图片保存到
SDImageCache
中,内存缓存和磁盘缓存同时保存,写文件到硬盘也在以单独 NSInvocationOperation
完成,避免拖慢主线程。
-
SDImageCache
在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
-
SDWebImage
也提供了UIButton+WebCache
等扩展来方便使用,具体的还需自行去查看源码。
-
SDWebImagePrefetcher
可以预先下载图片,方便后续使用。
工作流程图
SDWebImage的各个类及其提供的方法功能介绍:
各个类的方法及其关系图
SDWebImage中常用方法介绍:
UIImageView * img = [[UIImageView alloc]initWithFrame:CGRectMake(50, 100, 200, 200)];
//最简单的使用方法
[img sd_setImageWithURL:[NSURL URLWithString:@"http://pic22.nipic.com/20120714/9622064_105642209176_2.jpg"] placeholderImage:[UIImage imageNamed:@"占位图"]];
//下面方法能够提供占位图、下载进度、监听下载完成的功能
/*
其中options参数为SDWebImageOptions的位运算枚举,多个使用的时候用|隔开
SDWebImageRetryFailed = 1 << 0,:默认情况下,如果一个url在下载的时候失败了,那么这个url会被加入黑名单并且library不会尝试再次下载,这个flag会阻止library把失败的url加入黑名单(简单来说如果选择了这个flag,那么即使某个url下载失败了,sdwebimage还是会尝试再次下载他
SDWebImageLowPriority = 1 << 1,:默认情况下,图片会在交互发生的时候下载(例如你滑动tableview的时候),这个flag会禁止这个特性,导致的结果就是在scrollview减速的时候,才会开始下载(也就是你滑动的时候scrollview不下载,你手从屏幕上移走,scrollview开始减速的时候才会开始下载图片
SDWebImageCacheMemoryOnly = 1 << 2,:这个flag禁止磁盘缓存,只有内存缓存
SDWebImageProgressiveDownload = 1 << 3,:这个flag会在图片下载的时候就显示(就像你用浏览器浏览网页的时候那种图片下载,一截一截的显示(待确认))
SDWebImageRefreshCached = 1 << 4,:一个图片缓存了,还是会重新请求.并且缓存侧略依据NSURLCache而不是SDWebImage.URL不变,图片会更新时使用
SDWebImageContinueInBackground = 1 << 5,:启动后台下载,加入你进入一个页面,有一张图片正在下载这时候你让app进入后台,图片还是会继续下载(这个估计要开backgroundfetch才有用)
SDWebImageHandleCookies = 1 << 6,:可以控制存在NSHTTPCookieStore的cookies.
SDWebImageAllowInvalidSSLCertificates = 1 << 7,:允许不安全的SSL证书,在正式环境中慎用
SDWebImageHighPriority = 1 << 8,:默认情况下,image在装载的时候是按照他们在队列中的顺序装载的(就是先进先出).这个flag会把他们移动到队列的前端,并且立刻装载,而不是等到当前队列装载的时候再装载.
SDWebImageDelayPlaceholder = 1 << 9,:默认情况下,占位图会在图片下载的时候显示.这个flag开启会延迟占位图显示的时间,等到图片下载完成之后才会显示占位图.
SDWebImageTransformAnimatedImage = 1 << 10,:是否transform图片
*/
[img sd_setImageWithURL:[NSURL URLWithString:@"http://pic22.nipic.com/20120714/9622064_105642209176_2.jpg"]placeholderImage:[UIImage imageNamed:@"占位图"]options:SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
float currentProgress = (float)receivedSize/(float)expectedSize;
NSLog(@"进度%lf",currentProgress);
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
NSLog(@"下载完成");
}];
//取消所有的图片下载
[[SDWebImageManager sharedManager] cancelAll];
//继续图片下载
[[SDWebImageManager sharedManager] isRunning];
//获取磁盘存储的文件大小
[[SDImageCache sharedImageCache] getSize];
//返回当前路径缓存中是否存在对应的图片
[[SDWebImageManager sharedManager] cachedImageExistsForURL:@"" completion:^(BOOL isInCache) {
}];
//返回当前路径磁盘中是否存在对应的图片
[[SDWebImageManager sharedManager] diskImageExistsForURL:@"" completion:^(BOOL isInCache) {
}];
SDWebImage的下载设置
//下载
//设置超时时间,默认15秒
[[SDWebImageDownloader sharedDownloader] setDownloadTimeout:10];
//设置最大并行下载量默认为6
[[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:6];
/*
//下载方式
SDWebImageDownloaderFIFOExecutionOrder --默认以先进先出的方式来处理
SDWebImageDownloaderLIFOExecutionOrder --后进先出发,通过设置依赖的方式设置优先级
*/
[[SDWebImageDownloader sharedDownloader] setExecutionOrder:SDWebImageDownloaderFIFOExecutionOrder];
当我们遇到内存警告的时候SDWebImage该做些什么
//01--清除内存缓存
[[SDWebImageManager sharedManager].imageCache clearMemory];
//02--取消队列中的下载任务
[[SDWebImageManager sharedManager] cancelAll];
//清除磁盘缓存
[[SDWebImageManager sharedManager].imageCache clearDiskOnCompletion:nil];
网友评论