一、SDWebImage的基本使用
小编最早也只是会基本使用,但是后来企业导师和我说SDWebImage
的东西很多,只会基本使用是不够的。那么先来看看基本使用。SDWebImage的github地址
官方文档
·Objective-C
#import <SDWebImage/SDWebImage.h>
...
[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
Swift
import SDWebImage
imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
如果在SDWebImage5.0中除了基本图片他还引入了全新的图像支持机制(GIF)支持。
Objective-C
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
SDAnimatedImage *animatedImage = [SDAnimatedImage imageNamed:@"image.gif"];
imageView.image = animatedImage;
Swift
let imageView = SDAnimatedImageView()
let animatedImage = SDAnimatedImage(named: "image.gif")
imageView.image = animatedImage
二、github上SDWebImage的高级图
为了方便大家学习,小编这边把github上的SDWebImage 的架构设计图挪过来,大家可以看看。
从上图中我们可以大概的看出,整个库分为两层,Top Level
、Base Module
。
Top Level
:当UIImageView调用加载image方法,会进入SDWebImage中的UIImageView分类,在分类中调用负责加载UIImage的核心代码块ImageManager,其主要负责调度Image Cache/Image Loader,这两者分别从缓存或者网络端加载图片,并且又进行了细分。Cache中获取图片业务,拆分到了memory/disk(内存/外存)两个分类中;Image Loader(图片加载)中又分为从网络端获取或者从系统的Photos中获取。
Base Module
:获取到图片的二进制数据处理,二进制解压缩,二进制中格式字节判断出具体的图片类型。
三、部分源码解读
UIView+WebCache.m
由于分类中不能添加成员变量,所以UIView+WebCache.m
中使用了runtime关联了sd_imageURL图片的url、sd_imageProgress下载进度;sd_cancelCurrentImageLoad方法取消当前下载,sd_imageIndicator设置当前加载动画,sd_internalSetImageWithURL:内部通过SDWebImageManager调用加载图片过程并返回调用进度。
以sd_imageURL
为例,为属性重写setter、getter方法。
- (nullable NSURL *)sd_imageURL {
return objc_getAssociatedObject(self, @selector(sd_imageURL));
}
- (void)setSd_imageURL:(NSURL * _Nullable)sd_imageURL {
objc_setAssociatedObject(self, @selector(sd_imageURL), sd_imageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
objc_getAssociatedObject
、objc_setAssociatedObject
就是我们说的关联对象。在runtime.h文件中就可以找到它们的声明:
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
objc_setAssociatedObject 用于给对象添加关联对象,传入 nil 则可以移除已有的关联对象;
id objc_getAssociatedObject(id object, const void *key);
objc_getAssociatedObject 用于获取关联对象;
void objc_removeAssociatedObjects(id object);
objc_removeAssociatedObjects 用于移除一个对象的所有关联对象。
根据上图可以看到UIView+WebCache
中有两个核心的东西分别是Indicator
指示信号和Transition
过渡动画。
以及最重要的是sd_internalSetImageWithURL:
方法,用来 获取图片,并展示
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock {
if (context) {
// 复制以避免可变对象
context = [context copy];
} else {
context = [NSDictionary dictionary];
}
NSString *validOperationKey = context[SDWebImageContextSetImageOperationKey];
if (!validOperationKey) {
// 将操作键传递到下游,可用于跟踪操作或图像视图类
validOperationKey = NSStringFromClass([self class]);
SDWebImageMutableContext *mutableContext = [context mutableCopy];
mutableContext[SDWebImageContextSetImageOperationKey] = validOperationKey;
context = [mutableContext copy];
}
self.sd_latestOperationKey = validOperationKey;
//1.判断是否有正在执行的任务
//有正在进行的任务,那么取消下载任务
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
self.sd_imageURL = url;
SDWebImageManager *manager = context[SDWebImageContextCustomManager];
if (!manager) {
//处理接下来缓存数据和下载数据之间的逻辑
manager = [SDWebImageManager sharedManager];
} else {
// 删除此管理器以避免保留周期(管理器->加载程序->操作->上下文->管理器)
SDWebImageMutableContext *mutableContext = [context mutableCopy];
mutableContext[SDWebImageContextCustomManager] = nil;
context = [mutableContext copy];
}
BOOL shouldUseWeakCache = NO;
if ([manager.imageCache isKindOfClass:SDImageCache.class]) {
shouldUseWeakCache = ((SDImageCache *)manager.imageCache).config.shouldUseWeakMemoryCache;
}
//2.设置Placeholder
//SDWebImageDelayPlaceholder
//!(options & SDWebImageDelayPlaceholder)不需要延时加载
if (!(options & SDWebImageDelayPlaceholder)) {
if (shouldUseWeakCache) {
NSString *key = [manager cacheKeyForURL:url context:context];
//调用内存缓存以触发弱缓存同步逻辑,忽略返回值并继续正常查询
//不幸的是,这将导致两次内存缓存查询,但速度足够快
//将来可能会重新设计或删除弱缓存功能
[((SDImageCache *)manager.imageCache) imageFromMemoryCacheForKey:key];