SDWebImage的使用

为什么要使用SDWebImage

它有如下优点

  • UIImageView Button MapView大头钉 的Category 使用简单方便
  • 异步下载,一行代码调用,几乎无需配置
  • 默认硬盘和内存缓存,自动管理
  • 支持 WebP Gif格式
  • 有防止重复下载,下载失败重试等灵活的设置

SDWebImage总览

.
SDWebImage
	-
	|--SDWebImageCompat :一些兼容性相关的宏定义 
	|--SDWebImageOperation :只有一个 cancel 方法的 protocal
	|
	|--Downloader :下载模块
	|	|-- SDWebImageDownloader
	|	|-- SDWebImageDownloaderOperation
	|	
	|--Cache :内存和硬盘缓存模块
	|	|-- SDImageCache
	|
	|--Utils :
	|	|-- SDWebImageManager 将缓存和下载模块结合起来使用
	|	|-- SDWebImagePrefetcher 预下载图片
	|	|-- SDWebImageDecoder
	|
	|--Categories : UIKit 相关的Category,方便使用,还支持 MKAnnotationView
		|-- MKAnnotationView+WebCache
		|-- UIButton+WebCache
		|-- UIImageView+WebCache
	-
	... ...

使用

其实SDWebImage 的Readme 和Demo 已经讲解的很清楚了..

基本使用

导入头文件<SDWebImage/UIImageView+WebCache.h>

调用sd_setImageWithURL:placeholderImage:即可,缓存异步下载等默认都无需配置

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier] autorelease];
    }
    [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                      placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

    return cell;
}

这个方法下载完成有回调,可以进行自定义的操作

[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
	自定义操作
}];

额外的使用方式

可以导入Category设置UIButton的背景图片 UIImageView 设置Gif

UIButton+WebCache
- (void)sd_setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock

UIImage+GIF
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data

如果需要身份鉴定

设置
[SDWebImageManager sharedManager].imageDownloader.username = @"username";
[SDWebImageManager sharedManager].imageDownloader.password = @"pwd";
或者 
[SDWebImageManager sharedManager].imageDownloader.urlCredential = myUrlCredential;
其中之一

其它重要的属性

[SDWebImageManager.sharedManager.imageDownloader setValue:@"SDWebImage Demo" forHTTPHeaderField:@"AppName"]; //自定义头
SDWebImageManager.sharedManager.imageDownloader.executionOrder = SDWebImageDownloaderLIFOExecutionOrder; //下载任务的执行顺序 FIFO LIFO 执行顺序 ,后面会说到
maxConcurrentDownloads //最多同时下载的图片数量
downloadTimeout //下载超时 还可以设置失败后的操作 失败重试等
options:(SDWebImageOptions) //我们在调用下载图片的方法时,有可选的options参数 ,第二篇文章会说到

内存和磁盘缓存相关

下面的属性方法都以 [SDWebImageManager.sharedManager.imageCache xxx] 形式调用

NSUInteger maxMemoryCost  //缓存最多能占用多少内存,默认是无限大~,
NSUInteger maxMemoryCountLimit  //最多能缓存多少张图片
NSInteger maxCacheAge //最大缓存时间 默认一周
NSUInteger maxCacheSize  //最大磁盘缓存空间  

- (NSUInteger)getSize;  //同步获取磁盘缓存大小  
- (void)calculateSizeWithCompletionBlock:(SDWebImageCalculateSizeBlock)completionBlock;  //异步获取磁盘缓存大小 
- (NSUInteger)getDiskCount; //异步获取磁盘缓存文件数量  

- (void)cleanDisk; //cleanDisk 删除所有过期的图片 
- (void)clearMemory; //清除内存缓存

//无需手动调用上面的2个方法,SDWebImageCache会监听
UIApplicationDidReceiveMemoryWarningNotification 
UIApplicationWillTerminateNotification 
UIApplicationDidEnterBackgroundNotification 
通知来清除内存缓存和后台清理过期的磁盘缓存

但这个方法可以暴漏给用户 ,作为清除缓存的设置
[SDWebImageManager.sharedManager.imageCache clearDisk];

SDWebImage是由下载.缓存两部分组成的,我们可以单独使用任意一部分

UIImageView+WebCache category 中的下载任务调用的是 SDWebImageManager 中的方法,这个类将缓存和异步下载结合起来,我们也可以直接使用 SDWebImageManager

直接使用SDWebImageManager 下载图片,异步下载和缓存已经做好了.
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imageURL
                      options:0
                     progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                         // 进度更新
                     }
                     completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                         if (image) {
                             // 自定义操作
                         }
                     }];

SDWebImageManager 代理

@protocol SDWebImageManagerDelegate <NSObject>

@optional

/**
 * 当缓存中没有图片是是否需要下载图片 
 * @return 如果下载,返回 YES, 默认值 YES;
 */
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;

/**
 * 这个方法在图片被下载之后,放入缓存之前,我们可以在这里裁剪图片,添加圆角等,之后存入缓存.
 * NOTE: 这个方法在全局队列中异步后台执行,不会阻塞主线程.
 */
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;

@end

只使用Downloader 异步下载,不使用缓存

SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader];
[downloader downloadImageWithURL:imageURL
                         options:0
                        progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                            // 进度更新
                        }
                       completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
                            if (image && finished) {
                                // 自定义操作
                            }
                        }];

单独使用图片缓存

存
[[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey];
默认会在内存和磁盘中缓存图片,如果不需要磁盘缓存可以使用 storeImage:forKey:toDisk:

取
SDImageCache *imageCache = [[SDImageCache alloc] initWithNamespace:@"myNamespace"];
[imageCache queryDiskCacheForKey:myCacheKey done:^(UIImage *image) {
    // 如果缓存中存在图片,则 image!=nil
}];
默认会在内存和磁盘中查找缓存,如果不需要在磁盘中查找缓存,可以 imageFromMemoryCacheForKey:

缓存的Key

默认情况下 缓存的key是图片的 url 经过MD5加密生成的
每张图片被保存为一个文件,文件名类似 1d067b6f4457574b8165aef42643752e 
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];

如果图片的 url 是动态的, 或者一个Url对应的图片可能不同, 那么使用这个方法,给图片设置一个应用程序内唯一的Key

官方示例
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL *url) {
        url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
        return [url absoluteString];
    };

    // 其他初始化操作
    return YES;
}

在TableView中的使用注意

在SDWebImage的官方Demo

设置了
SDWebImageManager.sharedManager.imageDownloader.executionOrder = SDWebImageDownloaderLIFOExecutionOrder;

executionOrder 执行下载图片请求的顺序

  • 比如在我们用一个TableView,每一个Cell含一张图片,初始状态显示 1-9 号cell,当我们滑动之后屏幕中显示 31-39 号cell ,那么在滑动过程中我们调用sd_setImageUrl 39次, 这39个下载请求有先后顺序
  • 默认从 1-39 顺序执行图片请求,这个就是FIFO(First In First Out,先添加的最先执行),然而为了用户体验我们应该下载用户正在看的31-39号cell的图片, 也就是最后添加的9个请求, 这个就是LIFO(Last In First Out,最后加入队列的最先执行)
  • executionOrder的默认值为 SDWebImageDownloaderFIFOExecutionOrder,所以我们在TableView中使用视情况设置为 SDWebImageDownloaderLIFOExecutionOrder

补充

下载SDWebImage

如果你没有使用CocoaPods下载SDWebImage,通过Github DownLoad Zip 或者Git 客户端下载运行其Demo时,会运行失败,其中解析WebP格式图片使用的是Google的库,作为 submodule 没有被下载下来.

使用 git clone --recursive https://github.com/rs/SDWebImage.git 命令下载SDWebImage 及其subModule ,最好翻墙后在运行命令,否则也可能下载不完整.

下一篇 中我会分析 SDWebImage 源码中的下载模块的实现