一、我们先来了解一下SDWebImage的使用:
1、导入框架,引入头文件:
#import "UIImageView+WebCache.h"
也可以直接使用CocoaPods来引入和管理
(OC 如下)
platform :ios, '7.0'
pod 'SDWebImage', '~>3.8'
(swift)并且要确保添加了use_frameworks,iOS版本为8.0+
platform :ios, '8.0'
use_frameworks!
2、图片下载并缓存方法:
//得到当前图片的url
- (NSURL *)sd_imageURL;
// 异步下载图片并缓存
- (void)sd_setImageWithURL:(NSURL *)url;
// 异步下载图片并缓存,没下载完之前先显示占位图片,下载完之后再替换
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
/**
* 异步下载图片并缓存
* @param url 下载图片路径
* @param placeholder 占位图片,直到下载完成才替换
* @param options 下载图片选择方式(这个选项也就是3中要介绍的options选项)
*/
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
/**
* 异步下载图片并缓存,但没有占位图片,完成后可以在block中做事情
* @param url 下载图片url
* @param completedBlock
SDWebImageCompletionBlock:(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL)
block中可以得到下载图片,错误信息,缓存类型,下载图片地址 参数,给用户做相应操作
*/
- (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock;
/**
* 异步下载图片并缓存,提供占位图片,并完成后可以在block中做事情
* @param url 下载图片url
* @param placeholder 占位图片,直到下载完成才替换
* @param completedBlock
SDWebImageCompletionBlock:UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL)
block中可以得到下载图片,错误信息,缓存类型,下载图片地址 参数,给用户做相应操作
*/
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
/**
* 异步下载图片并缓存,不仅提供占位图,还可以设置下载方式:options,完成后可以在block中做事情
* @param url 下载图片路径
* @param placeholder 占位图片,直到下载完成才替换
* @param options 下载图片选择方式
* @param completedBlock 同上
*/
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock;
/**
* 异步下载图片并缓存,不仅提供占位图,还可以设置下载方式:options,同时可以监听下载进度,完成后可以在block中做事情
* @param url 下载图片路径
* @param placeholder 占位图片,直到下载完成才替换
* @param options 下载图片选择方式
* @param progress 图片下载进度
* SDWebImageDownloaderProgressBlock:NSInteger receivedSize(当前下载大小), NSInteger expectedSize(总大小)
* @param completedBlock 同上
*/
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
/**
* 异步下载图片并缓存,不仅提供占位图,还可以设置下载方式:options,同时可以监听下载进度,还可以提供下载大小,完成后可以在block中做事情
* @param url 下载图片路径
* @param placeholder 占位图片,直到下载完成才替换
* @param options 下载图片选择方式
* @param progress
* SDWebImageDownloaderProgressBlock:NSInteger receivedSize(当前下载大小), NSInteger expectedSize(总大小)
* @param completedBlock 同上
*/
- (void)sd_setImageWithPreviousCachedImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;,
3、options所有选项
//失败后重试
SDWebImageRetryFailed = 1 << 0,
//最低优先级,当正在进行UI交互时,自动暂停内部的一些下载操作
SDWebImageLowPriority = 1 << 1,
//只缓存内存
SDWebImageCacheMemoryOnly = 1 << 2,
//渐进式下载,显示的图像是逐步在下载
SDWebImageProgressiveDownload = 1 << 3,
//刷新缓存
SDWebImageRefreshCached = 1 << 4,
//后台下载
SDWebImageContinueInBackground = 1 << 5,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
SDWebImageHandleCookies = 1 << 6,
//允许使用无效的SSL证书
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
//高优先级下载
SDWebImageHighPriority = 1 << 8,
//延迟占位符
SDWebImageDelayPlaceholder = 1 << 9,
//改变动画形象
SDWebImageTransformAnimatedImage = 1 << 10,
/**
* By default, image is added to the imageView after download. But in some cases, we want to
* have the hand before setting the image (apply a filter or add it with cross-fade animation for instance)
* Use this flag if you want to manually set the image in the completion when success
*/
SDWebImageAvoidAutoSetImage = 1 << 11
4、内存处理:当app接收到内存警告时,我们要释放内存(可以在AppDelegate.m 的applicationDidReceiveMemoryWarning方法中释放,也可以在控制器的didReceiveMemoryWarning方法中释放)
SDWebImageManager *manager = [SDWebImageManager sharedManager];
// 取消正在下载的操作
[manager cancelAll];
// 清除内存缓存
[manager.imageCache clearMemory];
//释放磁盘的缓存
[manager.imageCache cleanDisk];
5、使用SDWebImageManager类:可以进行一些异步加载的工作
SDWebImageManager *manager = [SDWebImageManager sharedManager];
UIImage *cachedImage = [manager imageWithURL:url]; // 将需要缓存的图片加载进来
if (cachedImage) {
// 如果Cache命中,则直接利用缓存的图片进行有关操作
} else {
// 如果Cache没有命中,则去下载指定网络位置的图片,并且给出一个委托方法
[manager downloadWithURL:url delegate:self];
}
当然你的类要实现SDWebImageManagerDelegate协议,并且要实现协议的webImageManager:didFinishWithImage:方法。
// 当下载完成后,调用回调方法,使下载的图片显示
- (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)image {
}
6、独立的异步图像下载和独立的异步图像缓存
独立的异步图像下载
可能会单独用到异步图片下载,则一定要用downloaderWithURL:delegate:来建立一个SDWebImageDownloader实例。
SDWebImageDownloader *downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self];
这样SDWebImageDownloaderDelegate协议的方法imageDownloader:didFinishWithImage:被调用时下载会立即开始并完成。
独立的异步图像缓存
SDImageCache类提供一个创建空缓存的实例,并用方法imageForKey:来寻找当前缓存。
UIImage *myCachedImage = [SDImageCache sharedImageCache] imageFromKey:myCacheKey];
存储一个图像到缓存是使用方法storeImage: forKey:
[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey];
默认情况下,图像将被存储在内存缓存和磁盘缓存中。如果仅仅是想内存缓存中,要使用storeImage:forKey:toDisk:方法的第三个参数带一负值来替代。
来替代。
二、SDWebImage内部实现原理
SDImageCache是怎么做数据管理的?(如下图所示:)
图片解释:内存层面的相当是个缓存器,以Key-Value的形式存储图片。当内存不够的时候会清除所有缓存图片。用搜索文件系统的方式做管理,文件替换方式是以时间为单位,剔除时间大于一周的图片文件。当SDWebImageManager向SDImageCache要资源时,先搜索内存层面的数据,如果有直接返回,没有的话去访问磁盘,将图片从磁盘读取出来,然后做Decoder,将图片对象放到内存层面做备份,再返回调用层。
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、imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
12、通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。
13、将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
大体过程总结了一下就是这样的:
SD_WebImage主要SD_WebImageManager单例类来管理SD_WebImageDownloader和SD_ImageCache这两个单例类。
1.当执行下载操作的时候,SD_ImageCache会从内存图片缓存中找有没有这个图片,如果有,SD_ImageCacheDelegate就会通过一系列的回调到UIImageView+WebCache到前端展示图片,如果内存缓存没有->
2.会到硬盘缓存当中找,如果有,就会将图片添加到内存缓存中(这里注意一点,如果空闲内存过小,会先清空内存缓存)然后也是SD_ImageCacheDelegate通过一系列的回调到UIImageView+WebCache到前端展示图片;如果没有->
3.就需要用SD_WebImageDownloader开始下载图片,图片下载由NSURLConnection来做,实现相关的代理来判断图片下载中,下载完成,下载失败,当图片下载完成后会交给SD_WebImageDecoder做图片解码处理,然后也是通过一系列的回调到UIImageView+WebCache到前端展示图片。另外也会将下载好的图片保存到SD_ImageCache中。