1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
typedef NS_ENUM(NSInteger, SDImageCacheType) { /** * The image wasn't available the SDWebImage caches, but was downloaded from the web. 该图像是不可用的SDWebImage缓存,但是从网络下载的. */ SDImageCacheTypeNone, /** * The image was obtained from the disk cache. 图像从磁盘高速缓存获得. */ SDImageCacheTypeDisk, /** * The image was obtained from the memory cache. 图像从存储器高速缓存获得 */ SDImageCacheTypeMemory }; |
SDWebImage是iOS开发者经常使用的一个开源框架,这个框架的主要作用是:
一个异步下载图片并且支持缓存的UIImageView分类.
UIImageView+WebCache
我们最常用的方法就是这个:
1 |
[_fineImageView sd_setImageWithURL:picURL placeholderImage:nil]; |
现在开始我们一步步地看这个方法的内部实现:
1 2 3 |
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; } |
这里会调用下面这个方法:
1 2 3 4 |
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock |
我们看UIImageView+WebCache.h文件,我们可以发现为开发者提供了很多类似于- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
的方法.
这些方法最终都会调用- sd_setImageWithURL: placeholderImage: options: progress: completed:
,这个方法可以算是核心方法,下面我们看一下- sd_setImageWithURL: placeholderImage: options: progress: completed:
方法的实现:
首先执行
1 2 |
//移除UIImageView当前绑定的操作.当TableView的cell包含的UIImageView被重用的时候首先执行这一行代码,保证这个ImageView的下载和缓存组合操作都被取消 [self sd_cancelCurrentImageLoad]; |
接下来我们来看看[self sd_cancelCurrentImageLoad]
内部是怎么执行的:
1 2 3 4 5 |
- (void)sd_cancelCurrentImageLoad { [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"]; } //然后会调用UIView+WebCacheOperation的 - (void)sd_cancelImageLoadOperationWithKey:(NSString *)key |
UIView+WebCacheOperation
下面我们先来看看UIView+WebCacheOperation
里面都写了些什么:
UIView+WebCacheOperation
这个分类提供了三个方法,用于操作绑定关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#import #import "SDWebImageManager.h" @interface UIView (WebCacheOperation) /** * Set the image load operation (storage in a UIView based dictionary) 设置图像加载操作(存储在和UIView做绑定的字典里面) * * @param operation the operation * @param key key for storing the operation */ - (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key; /** * Cancel all operations for the current UIView and key 用这个key找到当前UIView上面的所有操作并取消 * * @param key key for identifying the operations */ - (void)sd_cancelImageLoadOperationWithKey:(NSString *)key; /** * Just remove the operations corresponding to the current UIView and key without cancelling them * * @param key key for identifying the operations */ - (void)sd_removeImageLoadOperationWithKey:(NSString *)key; |
为了方便管理和找到视图正在进行的一些操作,WebCacheOperation
将每一个视图的实例和它正在进行的操作(下载和缓存的组合操作)绑定起来,实现操作和视图一一对应关系,以便可以随时拿到视图正在进行的操作,控制其取消等,如何进行绑定我们在下面分析:
UIView+WebCacheOperation.m
文件内
- (NSMutableDictionary *)operationDictionary
用到了中定义的两个函数:
- objc_setAssociatedObject
- objc_getAssociatedObject
NSObject+AssociatedObject.h
123@interface NSObject (AssociatedObject)@property (nonatomic, strong) id associatedObject;@endNSObject+AssociatedObject.m
12345678@implementation NSObject (AssociatedObject)@dynamic associatedObject;-(void)setAssociatedObject:(id)object{objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}-(id)associatedObject {return objc_getAssociatedObject(self, @selector(associatedObject));}
objc_setAssociatedObject
作用是对已存在的类在扩展中添加自定义的属性 ,通常推荐的做法是添加属性的key最好是static char
类型的,通常来说该属性的key应该是常量唯一的.
objc_getAssociatedObject
根据key获得与对象绑定的属性.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
- (NSMutableDictionary *)operationDictionary { /* 这个loadOperationKey 的定义是:static char loadOperationKey; 它对应的绑定在UIView的属性是operationDictionary(NSMutableDictionary类型) operationDictionary的value是操作,key是针对不同类型视图和不同类型的操作设定的字符串 注意:&是一元运算符结果是右操作对象的地址(&loadOperationKey返回static char loadOperationKey的地址) */ NSMutableDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); //如果可以查到operations,就rerun,反正给视图绑定一个新的,空的operations字典 if (operations) { return operations; } operations = [NSMutableDictionary dictionary]; objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return operations; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key { // 取消正在下载的队列 NSMutableDictionary *operationDictionary = [self operationDictionary]; //如果 operationDictionary可以取到,根据key可以得到与视图相关的操作,取消他们,并根据key值,从operationDictionary里面删除这些操作 id operations = [operationDictionary objectForKey:key]; if (operations) { if ([operations isKindOfClass:[NSArray class]]) { for (id operation in operations) |