SDWebImage-源码学习笔记.png
2019.12.27 更新:最近发现 SDWebImage 升级到 5.0 以后加载 WebP 和 Gif 的方式也发生了改变,详见文末。
一、前言
前段时间对项目中使用的 SDWebImage 进行了一次升级 (3.7.6 → 4.4.2),升级过程中遇到了一些问题,于是又把源码读了一遍,为了记录读码过程,就有了这个系列:
- SDWebImage 源码学习笔记·前传 ☞ 升级 4.0 / 5.0 后适配 WebP/GIF
- SDWebImage源码学习笔记 ☞ 结构及基本流程
- SDWebImage源码学习笔记 ☞ SDWebImageManager
- SDWebImage源码学习笔记 ☞ SDWebImageDownloader
- SDWebImage源码学习笔记 ☞ SDImageCache
本篇是第 1 篇,主要记述了升级过程中的遇到的问题及处理方案。
二、升级
现在转回到本篇的主要内容,首先当然是升级了,不过最新版的 SDWebImage 里边分了几个子 pod ,默认下载不全。为了满足我们的日常使用要求,还需要加上 WebP 和 GIF 这两个子 pod:
platform :ios, '7.0'
pod 'SDWebImage', '~> 4.0'
pod 'SDWebImage/WebP'
pod 'SDWebImage/GIF'
不过,在执行 pod install
的时候,发现 pod 'SDWebImage/WebP'
卡在了 Installing libwebp (0.6.0)
的地方。
据说 WebP 的解析库是 Google 的开源库,目前还无法直接使用,可以使用github上的镜像文件,这个网上很容易搜到,示例见文末参考。
完成后 pod 内部的结构如下:
SDWebImage4.0.png
三、使用
为叙述方便,此处将图片的 URL 定义成了宏:
#define URL_Normal [NSURL URLWithString:@"此处是 普通静态图 地址"]
#define URL_WebP_Normal [NSURL URLWithString:@"此处是 静态 WebP 地址"]
#define URL_WebP_Dynamic [NSURL URLWithString:@"此处是 动态 WebP 地址"]
#define URL_GIF [NSURL URLWithString:@"此处是 GIF 地址"]
第一种方案
- png/jpg,直接使用 SDWebImage 提供的普通方法即可。
- WebP,只要导入了 WebP 的子 pod,直接使用普通方法即可正常加载静态、动态的 WebP。
- GIF,此处使用了 FLAnimatedImageView 代替 UIImageView 来展示 GIF。因为 SDWebImage4.0 以后,如果继续
直接
使用 UIImageView 将只展示 GIF 的第一帧,可以使用推荐的 FLAnimatedImageView 替换 UIImageView。
// 普通静态图
UIImageView *imgV = [[UIImageView alloc] initWithFrame:CGRectMake(125, 70, 160, 160)];
imgV.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:imgV];
[imgV sd_setImageWithURL:URL_Normal];
// WebP
UIImageView *imgVB = [[UIImageView alloc] initWithFrame:CGRectMake(125, 70+160+10, 160, 160)];
imgVB.backgroundColor = [UIColor lightGrayColor];
imgVB.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:imgVB];
// WebP 静态图
// [imgVB sd_setImageWithURL:URL_WebP_Normal];
// WebP 动态图
[imgVB sd_setImageWithURL:URL_WebP_Dynamic];
// GIF
FLAnimatedImageView *imgView = [[FLAnimatedImageView alloc] initWithFrame:CGRectMake(125, 70+160+10+160+10, 160, 200)];
imgView.backgroundColor = [UIColor lightGrayColor];
imgView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:imgView];
[imgView sd_setShowActivityIndicatorView:YES];
[imgView sd_setImageWithURL:URL_GIF
placeholderImage:[UIImage imageNamed:@"placeholder"]
options:1];
第二种方案
统一都使用 UIImageView 展示图片,不过和上边的第一种方案有以下不同:
- 使用
SDWebImageManager
的loadImageWithURL: options: progress: completed:
方法下载图片; - 根据得到的 data 判断图片类型:
SDImageFormat format = [NSData sd_imageFormatForImageData:data];
,基本原理是根据 data 的第一个字节来判断; - WebP 使用专用方法
sd_imageWithWebPData:
解码; - GIF 也使用专用方法
sd_animatedGIFWithData:
解码。
UIImageView *gifView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 70+160+10+160+10+200+10, kScreenW-20, 200)];
gifView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:gifView];
self.imgView = gifView;
SDWebImageManager *mgr = [SDWebImageManager sharedManager];
__weak typeof(self) weakSelf = self;
[mgr loadImageWithURL:URL_GIF // URL_WebP_Dynamic // URL_WebP_Normal // URL_Normal
options:1
progress:nil
completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL)
{
SDImageFormat format = [NSData sd_imageFormatForImageData:data];
switch (format) {
case SDImageFormatGIF:
weakSelf.imgView.image = [UIImage sd_animatedGIFWithData:data];
break;
case SDImageFormatWebP:
weakSelf.imgView.image = [UIImage sd_imageWithWebPData:data];
break;
case SDImageFormatPNG:
case SDImageFormatJPEG:
weakSelf.imgView.image = image;
break;
default:
break;
}
}];
第三种方案
自定义 HHImageView,在它的 init 系列方法中添加了对 GIF 的解析:
[[SDWebImageCodersManager sharedInstance] addCoder:[SDWebImageGIFCoder sharedCoder]];
这种方案对最终的调用方来说,非常简洁,不需要对各种图片区别对待。
HHImageView *customView = [[HHImageView alloc] initWithFrame:CGRectMake(125, 70, 160, 160)];
customView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:customView];
[customView sd_setShowActivityIndicatorView:YES];
// 静态图
// [customView sd_setImageWithURL:URL_Normal];
// WebP 动图
// [customView sd_setImageWithURL:URL_WebP_Normal];
// WebP 静态图
// [customView sd_setImageWithURL:URL_WebP_Dynamic];
// GIF
[customView sd_setImageWithURL:URL_GIF];
2019.12.27 更新:
- 5.0 之后的版本中,默认添加了对 Gif 的支持,也就是说,需要移除 podfile 中的
pod 'SDWebImage/GIF'
(不移除的话,pod install/update 会报错),然后直接使用加载 png/jpg 的方法就可以加载 Gif 图了,比如:imageViewA.sd_setImage(with: URL(string: "http://hbimg.b0.upaiyun.com/43efd35d1e9cadc6d8ff5cdc5faccec06f1082bb4efc4-o8K27E_fw658"), completed: nil) // 皮卡丘揉脸的动画^_^
- 对于 WebP,将之前的 subspec 抽出来,创建了一个单独的库
SDImageWebPCoder
,使用时需要两步操作:
- 在 podfile 文件中用下边的内容替换之前的
pod 'SDWebImage/GIF'
pod 'SDImageWebPCoder'
- 使用前,先给
SDImageCodersManager
添加一个 coder:WebPCoder
,如下:let WebPCoder = SDImageWebPCoder.shared SDImageCodersManager.shared.addCoder(WebPCoder)
然后,就可以使用通用的方法加载 WebP 了,示例代码如下:
// 静态图 imageViewA.sd_setImage(with: URL(string: "https://www.gstatic.com/webp/gallery/2.webp"), completed: nil) // 动图 imageViewB.sd_setImage(with: URL(string: "http://littlesvr.ca/apng/images/world-cup-2014-42.webp"), completed: nil)
本文完整示例代码见: HHSDWebImageStudy