SDWebImage源码阅读笔记

SDWebImage的结构
首先来看SDWebImageManager类,头文件中有如下内容:
SDWebImageOptions

定义基本的配置选项,简单翻译了一下注释

  • SDWebImageRetryFailed 默认,当从一个URL下载失败,这个URL会被加入黑名单,之后不会重试。不过黑名单是存在内存中的,所以当程序下次运行时还是有机会重新尝试下载这个图片的。
  • SDWebImageLowPriority 默认,图片会在UI交互进行交互的时候下载,这个选项可以禁用这个特性,将下载延迟到UIScrollView停止滚动之后
  • SDWebImageCacheMemoryOnly 禁用磁盘缓存
  • SDWebImageProgressiveDownload 变下载边显示,默认是下载完成后才显示
  • SDWebImageRefreshCached即使图片被缓存,也会遵守HTTP响应缓存控制,在远端刷新时重新下载。SDWebImage磁盘缓存管理将被NSURLCache代替,这将导致轻微的性能下降。这个选项有助于处理同一个URL下图片不同的情况。 如果缓存图片被刷新,完成的block回调被已缓存的图片和最终的图片各调用一次。
  • SDWebImageContinueInBackground 在iOS4以上系统,启用后台下载
  • SDWebImageHandleCookies cookie管理
  • SDWebImageAllowInvalidSSLCertificates 允许不受信任的SSL证书,用于测试。
  • SDWebImageHighPriority 默认的,图片按顺序加载,这个选项将图片移动到队列最前面
  • SDWebImageDelayPlaceholder 默认的,占位图在图片加载时加载,这个选项会延迟占位图的加载到图片完成加载之后
  • SDWebImageTransformAnimatedImage 由于大多数转化代码可能会损坏图片动画,通常是不对其调用transformDownloadedImage 代理方法,使用这个枚举来启用
  • SDWebImageAvoidAutoSetImage 默认情况,图片会在下载后添加到imageView,这个选项允许你手动管理图片当图片下载好之后。

接下来是代理SDWebImageManagerDelegate的定义:
-(BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;

当这个图片不在缓存中,将要被下载时调用

-(UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)imagewithURL:(NSURL *)imageURL;

允许图片在被下载完成后缓存到磁盘和内存之前立即被转换(转换transform应该就是将二进制数据格式化吧我猜)。这个方法在子线程执行以防止阻碍主线程。

接下来是一段简单的使用说明:
SDWebImageManager是其他category的前置类,即其他category都是使用SDWebImageManager进行下载图片的。SDWebImageManager将下载器(SDWebImageDownloader)和缓存(SDImageCache)链接起来。你可以使用这个类直接下载和缓存图片,而不需要使用UIView,例如

[managerdownloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOLfinished, NSURL *imageURL) {
    if(image) {
      // do something with image
    }
}];

然后是SDWebImageManager的属性和方法的定义。值得说明的是:

@property (nonatomic, copy) SDWebImageCacheKeyFilterBlock cacheKeyFilter;

缓存过滤器是一个block,SDWebImageManager需要将一个URL转换为缓存的key时使用它。它可以移除URL的动态部分,下面是例子:

[[SDWebImageManagersharedManager] setCacheKeyFilter:^(NSURL *url) {
   url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
   return [url absoluteString];
}];
    

其他的方法基本上都是见名知义的,就不需要过多解释了。来到.m文件,三百多行代码中有足足180行是

- (id <SDWebImageOperation>)downloadImageWithURL:options:progress:completed:方法的实现,所以只要看看这个方法即可。

首先是一个断言(我自己几乎从来没用过断言,以后应该改进啊),当completed block为空的时候会触发断言。然后作者非常周全的考虑到了很多人会犯的一个错误是将string直接作为URL参数传入,XCode不会抛出警告,所以作者在这里判断并将字符串作为参数初始化一个NSURL对象并赋值给url。然后又判断url参数是否为NSURL,以防止被传入一个错误的类型。

接下来,作者使用线程锁检查url是否在黑名单中,并判断url的长度是否为0,最后再对参数做一次检查😅。然后将当前的操作添加到一个集合中去,用于取消下载等操作。

终于到正戏了,首先检查磁盘缓存,细节我就不每一行都解释了,包括是否操作被取消了,即时调用代理方法,根据配置做不同的操作等等,基本都是逻辑判断了。最后返回操作对象。

迫不及待要看看平时最常用的UIImageView+WebCache这个分类了,看看头文件,方法不多,而且功能都很具体,直接看最常用的- (void)sd_setImageWithURL:(NSURL*)url;方法吧。

嗯,只有一句,[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];这个在意料之中的,平时自己封装工具也经常这么干。点进去接着看。

这下进入正菜了。首先取消当前的加载任务,因为是ImageView 的分类,一个ImageView自然只需要加载一个image,很好,继续。runtime闪亮登场!objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);这个也是runtime里很常用的一个函数,将一个属性绑定给一个对象。这里将url绑定给了imageView,这样imageView就有了url这个属性。接下来处理了一下占位图和ActivityIndicatorView。然后果然看到了SDWebImageManager的- (id <SDWebImageOperation>)downloadImageWithURL:options:progress:completed:方法。然后就是在完成的回调里面各种判断和执行完成回调了。

可以看到,SDWebImage的设计方式很合理,首先定义基本的管理类来管理这个工具的核心功能——对于SDWebImage就是下载(SDWebImageDownloader)和缓存(SDImageCache)。具体的功能分别在对应的类中实现。最后通过分类的形式创建出具体方便的使用方式和场景。一般的工具类都可以借鉴这种设计方式。

最后附带一个SDWebImageCompat类的简介,对于想要公开的代码库,兼容性是很重要的问题,而这些内容在一般的具体业务中很少被考虑到。

#ifdef __OBJC_GC__
#errorSDWebImage does not support Objective-C Garbage Collection
#endif
//不支持OC的垃圾回收机制
#if IPHONE_OS_VERSION_MIN_REQUIRED != 20000 &&IPHONE_OS_VERSION_MIN_REQUIRED < _IPHONE5_0
#errorSDWebImage doesn't support Deployment Target version < 5.0
#endif
//不支持iOS5以前的版本
#if!TARGET_OS_IPHONE
#import <AppKit/AppKit.h>
#ifndefUIImage
#defineUIImage NSImage
#endif
#ifndefUIImageView
#defineUIImageView NSImageView
#endif
#else
//在Mac下将UIKit控件定义为AppKit控件,用于支持macOS

#ifndefNS_ENUM
#defineNS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif

#ifndefNS_OPTIONS
#defineNS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
//定义 NS_ENUM 和 NS_OPTIONS(用于支持较早的OC版本?)

#ifOS_OBJECT_USE_OBJC
   #undef SDDispatchQueueRelease
   #undef SDDispatchQueueSetterSementics
   #define SDDispatchQueueRelease(q)
   #define SDDispatchQueueSetterSementics strong
#else
#undefSDDispatchQueueRelease
#undefSDDispatchQueueSetterSementics
#defineSDDispatchQueueRelease(q) (dispatch_release(q))
#defineSDDispatchQueueSetterSementics assign
#endif
//定义了两个类型,但是不明白为什么要这么定义😅

#if!__has_feature(objc_arc)
#errorSDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arcflag
#endif
//声明SDWebImage 只支持ARC
 
NSString *constSDWebImageErrorDomain = @"SDWebImageErrorDomain";
//最后定义了SDWebImage 的错误域,用于输出错误信息。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容