前言
CSDN地址:http://blog.csdn.net/game3108/article/details/52700626
本文的中文注釋代碼demo更新在我的github上。
上篇文章講解的了SDWebImage的Utils部分楔壤,這篇講講一下最后的Categories部分饶碘。
Categories
Categories包含以下幾個類文件:
- MKAnnotationView+WebCache
- NSData+ImageContentType
- UIButton+WebCache
- UIImage+GIF
- UIImage+MultiFormat
- UIImage+WebP
- UIImageView+HighlightedWebCache
- UIImageView+WebCache
- UIView+WebCacheOperation
這邊只介紹一下UIView+WebCacheOperation
與UIImageView+WebCache
,其他文件類似殖侵,這里也不多展開了,在github的注釋里會盡量都看一遍。
UIView+WebCacheOperation
UIView+WebCacheOperation主要通過associateObject的方式和屎,去緩存和取消、刪除運行的操作春瞬。
相關(guān)方法定義如下:
/**
設(shè)置圖片的load操作(存入一個uiview的字典)
@param operation 操作
@param key 存入的key
*/
- (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key;
/**
取消當前uiview的key的操作
@param key 存入的key
*/
- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key;
/**
移除當前uiview的key的操作柴信,并且不取消他們
@param key 存入的key
*/
- (void)sd_removeImageLoadOperationWithKey:(NSString *)key;
相關(guān)實現(xiàn):
static char loadOperationKey;
- (NSMutableDictionary *)operationDictionary {
//通過associateobject去存入和獲取dictionaryu
NSMutableDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey);
if (operations) {
return operations;
}
operations = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return operations;
}
- (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key {
//先取消操作
[self sd_cancelImageLoadOperationWithKey:key];
//然后獲取dictionary并存入
NSMutableDictionary *operationDictionary = [self operationDictionary];
[operationDictionary setObject:operation forKey:key];
}
- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key {
// Cancel in progress downloader from queue
//獲取dictionary,并且取消在queue中的操作
NSMutableDictionary *operationDictionary = [self operationDictionary];
id operations = [operationDictionary objectForKey:key];
if (operations) {
//數(shù)組的話獲取內(nèi)部所有的取消
if ([operations isKindOfClass:[NSArray class]]) {
for (id <SDWebImageOperation> operation in operations) {
if (operation) {
[operation cancel];
}
}
//如果是實現(xiàn)SDWebImageOperation契約宽气,直接取消
} else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){
[(id<SDWebImageOperation>) operations cancel];
}
[operationDictionary removeObjectForKey:key];
}
}
- (void)sd_removeImageLoadOperationWithKey:(NSString *)key {
//獲取dictionary并直接刪除key
NSMutableDictionary *operationDictionary = [self operationDictionary];
[operationDictionary removeObjectForKey:key];
}
UIImageView+WebCache
UIImageView+WebCache就是UIImage用到的sdwebimage的category随常,用戶最外層的調(diào)用方式。
這邊貼其中最基礎(chǔ)的操作方法的定義和實現(xiàn):
/**
通過url萄涯,設(shè)置imageview的image绪氛,placeholder和設(shè)置
下載方式異步并且緩存
@param url 圖片url
@param placeholder 初始化圖片
@param options 下載圖片方式
@param progressBlock 進度block回調(diào)
@param completedBlock 完成block回調(diào)
*/
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
//取消當前的圖片下載
[self sd_cancelCurrentImageLoad];
//保存url
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//如果沒有SDWebImageDelayPlaceholder則先設(shè)置placeholder圖
if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
self.image = placeholder;
});
}
//有url進行下載操作
if (url) {
// check if activityView is enabled or not
//是否需要顯示loading標簽圖
if ([self showActivityIndicatorView]) {
[self addActivityIndicator];
}
//下載圖片
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
//去掉可能存在的loadting圖
[wself removeActivityIndicator];
if (!wself) return;
dispatch_main_sync_safe(^{
if (!wself) return;
//不自動設(shè)置圖片
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
{
completedBlock(image, error, cacheType, url);
return;
}
//設(shè)置圖片
else if (image) {
wself.image = image;
[wself setNeedsLayout];
} else {
//沒有圖片設(shè)置默認圖
if ((options & SDWebImageDelayPlaceholder)) {
wself.image = placeholder;
[wself setNeedsLayout];
}
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
//緩存operation的key為load
[self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
} else {
//沒有url直接去掉loading圖
dispatch_main_async_safe(^{
[self removeActivityIndicator];
//返回錯誤給外面的block
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
}
總結(jié)
到這里,SDWebImage就算全部解析完了窃判。
我個人感覺钞楼,里面比較精髓的是處理圖片的一些細節(jié),比如gif圖片袄琳,還有decode圖片询件,用空間換時間等一些做法,這些細節(jié)的實現(xiàn)是整個圖片處理的基礎(chǔ)唆樊。
在框架上SDWebImage也是進行了多層的封裝宛琅,將最基礎(chǔ)的網(wǎng)絡(luò)操作封裝成operation,再此基礎(chǔ)上再往上封裝一層緩存層逗旁,并用一個manager去進行管理嘿辟。而用戶的使用調(diào)用都在category中實現(xiàn)相應(yīng)的方法舆瘪。
據(jù)說現(xiàn)在正在做4.0版本,會有一些大的變化改動红伦,可以期待一下英古。