转载

[SourceRead] SDWebImage-1

SDWebImage 作为一个将服务器远程的图片获取到UIImageView上显示的一个第三方类库,于我而言,最为常用的API莫过于 -sd_setImageWithURL: placeholderImage: 方法。不妨以此入手,拨开它源代码的神秘面纱。

[SourceRead] SDWebImage-1

点入.m文件,发现上图中从上至下的一列方法,都依次指向相邻的下一个方法,不过在上层调用时个别参数置为 nil0 。直到 -sd_setImageWithURL: placeholderImage:options:progress:completed: ,方见端倪。

- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {     [self sd_cancelCurrentImageLoad];     objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // [1]      if (!(options & SDWebImageDelayPlaceholder)) { // [2]         dispatch_main_async_safe(^{             self.image = placeholder;         });     } ... } 

[1]objc_setAssociatedObject

1. 这货是什么?

根据苹果的 官方文档 :

objc_setAssociatedObject 是Objective-C运行时的一个函数,它可以将两个对象关联起来。这个函数需要四个参数:原对象,一个键,一个值,和一个关联策略的常量。其中,键是一个void指针。

  • 每个关联的键都必须是唯一的。通常的做法是使用一个静态变量。
  • 关联策略指定了被关联的对象是assigned,retained,copied还是atomic/nonatomic。这个形式和声明property是类似的。可以用常量来指定这种关系。

2. 什么场景下会使用?

abbood 将它的使用场景归结为如下几点:

(1)给类别(category)添加实例变量。

假设你想给你不能修改的对象(比如说苹果官方提供的对象,UIImage、UILabel神马的。注意:我们这里讨论的是修改对象本身,不包括将其子类化。)的类别中添加个自定义的属性( 这几乎是Objective-C最大的缺点 ),比如说,我们想给 UIImage 添加一个title的属性。

// UIImage-Title.h: @interface UIImage(Title) @property(nonatomic, copy) NSString *title; @end   // UIImage-Title.m: #import <Foundation/Foundation.h> #import <objc/runtime.h>  static char titleKey;  @implementation UIImage(Title) - (NSString *)title {     return objc_getAssociatedObject(self, &titleKey); }  - (void)setTitle:(NSString *)title {     objc_setAssociatedObject(self, &titleKey, title, OBJC_ASSOCIATION_COPY); } @end 

(2)动态地给对象添加状态信息,而这个对象的实例变量即便结合KVO也不能达到目的。(有点拗口,慢慢理解。。)

意思是说,你的对象只有在runtime期间(也就是说,动态地)才能获取状态信息。所以,尽管你可以把状态信息存在实例变量中,但实际上你是要在runtime期间把这个信息和对象绑定起来、并且动态地把它和另一个对象关联,要强调的是 这是一个对象的动态状态 这个事实。

如下是一个不错的 例子 中的一个片段,在这个例子中,关联对象使用了KVO通知,但KVO并不是关联对象的必要条件。

static char BOOLRevealing;  - (BOOL)isRevealing {     return [(NSNumber*)objc_getAssociatedObject(self, &BOOLRevealing) boolValue]; }   - (void)_setRevealing:(BOOL)revealing {     [self willChangeValueForKey:@"isRevealing"];     objc_setAssociatedObject(self, &BOOLRevealing,         [NSNumber numberWithBool:revealing], OBJC_ASSOCIATION_RETAIN_NONATOMIC);     [self didChangeValueForKey:@"isRevealing"]; } 

引一段 SDWebImage 中的代码,纯正的、不含KVO的长这样子:

- (void)setShowActivityIndicatorView:(BOOL)show{     objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, [NSNumber numberWithBool:show], OBJC_ASSOCIATION_RETAIN); }  - (BOOL)showActivityIndicatorView{     return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue]; } 

其中, TAG_ACTIVITY_SHOW 的定义如下:

static char TAG_ACTIVITY_SHOW; 

3. 此处作用

所以,这里相当于给UIImageView的category添加了一个 imageURLKey 的属性,我猜想,是用来表示图片资源的唯一性的key。

[2]&

为什么这里用 & 而不是 && 呢?

趁机捡一捡基础知识:

& 是按位运算的双目运算符,功能是参与将运算的两个数各自对应的二进位相与。

例如:9&5可以写算式:00001001 & 00000101 = 00000001,即 9 & 5 = 1。

&& 检查第一个操作数的值,如果为false,就不再处理第二个操作数,直接返回false。

所以,这里的 (options & SDWebImageDelayPlaceholder) ,是两个枚举值进行按位运算,而非我们平常写的true/false的布尔判断。

随手点入枚举值的定义,发现这一堆:

typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {     /**      * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.      * This flag disable this blacklisting.      */     SDWebImageRetryFailed = 1 << 0, // [3]      /**      * By default, image downloads are started during UI interactions, this flags disable this feature,      * leading to delayed download on UIScrollView deceleration for instance.      */     SDWebImageLowPriority = 1 << 1,      /**      * This flag disables on-disk caching      */     SDWebImageCacheMemoryOnly = 1 << 2,     ... }; 

而其实 SDWebImageDelayPlaceholder 正是这一群枚举值中的一个,所以猜测,这句代码的意思是说,传入的 optionSDWebImageDelayPlaceholder 时该如何如何……(可为嘛曲曲折折地不直说呢?=_=|||)

[3]<<

<< 为按位左移运算符。具体它 是什么以及怎样运算 ,这里略去不提了。简单举例如下:

1 << 2 即 1 * 4 1 << 3 即 1 * 8 

Ref:

  • http://stackoverflow.com/questions/5909412/what-is-objc-setassociatedobject-and-in-what-cases-should-it-be-used/16313377#16313377

  • Mattt的真迹: http://nshipster.com/associated-objects/

  • 中文版: http://nshipster.cn/associated-objects/
原文  http://www.calios.gq/2016/01/28/SourceRead-SDWebImage-1/
正文到此结束
Loading...