SDWebImage源码学习之由浅入深一
来源:互联网 发布:杭州火车东站到淘宝城 编辑:程序博客网 时间:2024/06/14 11:22
本次学习从SDWebImage 常用的图片加载开始 ,由浅入深的剖析实现过程
UIImageView *imgV = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; [imgV sd_setImageWithURL:[NSURL URLWithString:@""] placeholderImage:nil];
首先进入方法 ,该方法是UIImageView 的分类中实现 UIImageView+WebCache.h
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];}
继续深入
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { // 此处为UIImageView 的父类UIView 的分类方法 UIView+WebCache [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:nil setImageBlock:nil progress:progressBlock completed:completedBlock];}
查看该方法详细实现。分析见注释
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options operationKey:(nullable NSString *)operationKey setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { // 首先会根据operationKey 传入的值来设置validOperationKey,当为nil时,设置为当前类名的字符串 // 我们在调用 sd_setImageWithURL: placeholderImage: 时,这里传入的是nil 所以此处validOperationKey = @"UIImageView" NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); // 该方法将根据validOperationKey的值去取消对应的图片加载任务 // 该方法的详细实现在下面 [self sd_cancelImageLoadOperationWithKey:validOperationKey];// 将当前url 通过imageURLKey 与self 绑定,由于self不同,这样就实现了 url 与对应的UIImageView绑定。 objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);// 在本例的简单调用中options = 0,所以 判断为真,进入分支// dispatch_main_async_safe() 这个宏是为了判断是否在主线程,如果不在则回到主线程调用。其实现见下 if (!(options & SDWebImageDelayPlaceholder)) { dispatch_main_async_safe(^{// 确保在主线程下调用// 此处由参数可见 是为了先设置placeholder 即占位图,实现没有图片时显示占位图,本例中 placeholder,setImageBlock 参数均为nil// 该方法实现见下 [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; }); } if (url) { // check if activityView is enabled or not if ([self sd_showActivityIndicatorView]) { [self sd_addActivityIndicator]; } __weak __typeof(self)wself = self; id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; [sself sd_removeActivityIndicator]; if (!sself) { return; } dispatch_main_async_safe(^{ if (!sself) { return; } if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) { completedBlock(image, error, cacheType, url); return; } else if (image) { [sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock]; [sself sd_setNeedsLayout]; } else { if ((options & SDWebImageDelayPlaceholder)) { [sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; [sself sd_setNeedsLayout]; } } if (completedBlock && finished) { completedBlock(image, error, cacheType, url); } }); }]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { dispatch_main_async_safe(^{ [self sd_removeActivityIndicator]; if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; completedBlock(nil, error, SDImageCacheTypeNone, url); } }); }}
dispatch_main_async_safe() 的实现,
dispatch_queue_get_label获取当前队列标签,使用strcmp()函数和主线程队列标签比较
#ifndef dispatch_main_async_safe#define dispatch_main_async_safe(block)\ if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\ block();\ } else {\ dispatch_async(dispatch_get_main_queue(), block);\ }#endif
该方法实现在UIView的分类UIView+WebCacheOperation
typedef NSMutableDictionary<NSString *, id> SDOperationsDictionary;- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key { // Cancel in progress downloader from queue SDOperationsDictionary *operationDictionary = [self operationDictionary]; id operations = operationDictionary[key]; if (operations) { if ([operations isKindOfClass:[NSArray class]]) { for (id <SDWebImageOperation> operation in operations) { if (operation) { [operation cancel]; } } } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){ [(id<SDWebImageOperation>) operations cancel]; } [operationDictionary removeObjectForKey:key]; }}
- (SDOperationsDictionary *)operationDictionary {// 通过变量绑定的方式,获取到operations SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); if (operations) { return operations; }// 第一次进入时,operations需要新创建,并进行变量绑定给loadOperationKey,然后返回 operations = [NSMutableDictionary dictionary]; objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return operations;}
- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock { if (setImageBlock) { // 本例中为nil setImageBlock(image, imageData); return; }// 下面代码就比较简单了,根据self的类执行不同方法设置占位图。 #if SD_UIKIT || SD_MAC // 平台兼容适配宏 if ([self isKindOfClass:[UIImageView class]]) { UIImageView *imageView = (UIImageView *)self; imageView.image = image; }#endif#if SD_UIKIT if ([self isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton *)self; [button setImage:image forState:UIControlStateNormal]; }#endif}
阅读全文
0 0
- SDWebImage源码学习之由浅入深一
- SDWebImage源码学习之由浅入深 二
- 由浅入深学习JavaScript(一)
- SDWebImage 学习一
- SDWebImage源码解析(一)
- 一行行看SDWebImage源码(一)
- SDWebImage 源码阅读(一)
- 解读SDWebImage源码之UIImageView
- SDWebImage源码解读 之SDWebImageCompat
- SDWebImage源码解读 之SDWebImageDecoder
- SDWebImage源码解读 之SDWebImageDownloaderOperation
- SDWebImage源码解读 之SDWebImageDownloader
- SDWebImage源码解读之 SDWebImageManager
- SDWebImage源码解读 之SDWebImagePrefetcher
- SDWebImage源码解读之 分类
- SDWebImage源码解读之分类
- Spring源码由浅入深系列一 简介
- Android:Dagger2学习之由浅入深
- mt2503[Language]申请孟加拉语矢量字库过 BTRC的patch包
- ToolBar的使用
- 微信公众号开发DEMO(包括登陆和支付)
- python函数参数带星号*
- Oracle的out参数
- SDWebImage源码学习之由浅入深一
- iOS编译过程的原理和应用
- 在应用程序中调用Oracle存储过程和存储函数
- NLP︱高级词向量表达——FastText(简述、学习笔记)
- Linux下安装java运行环境
- 例 6.4 将一个二维数组行和列的元素互换,存到另一个二维数组中。
- Junit4快速入门
- MII与RMII接口的区别
- iOS-贝塞尔曲线之自定义饼图