基础

SDWebImage 360°无死角分析之整理

2019-05-16  本文已影响30人  王技术

打算用几篇文章整理一下 SDWebImage 的源码
源码有点小多, 决定把每个模块分开来整理
这其中包括 : 调度模块、下载模块、缓存模块、解码模块和一些代码整理
调度模块看这里
缓存模块看这里
下载模块看这里
解码模块看这里
整理模块看这里


本文是一些代码整理

1> NS_OPTIONS与位运算

NS_OPTIONS用来定义位移相关操作的枚举值
当一个枚举变量需要携带多种值的时候就需要
参考UIKit.Framework的头文件
可以看到大量的枚举定义
在SDWebImage 的例子有 SDWebImageOptions 枚举值 :

typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
    SDWebImageRetryFailed = 1 << 0,
    SDWebImageLowPriority = 1 << 1,
    SDWebImageCacheMemoryOnly = 1 << 2,
    SDWebImageProgressiveDownload = 1 << 3,
    SDWebImageRefreshCached = 1 << 4,
    SDWebImageContinueInBackground = 1 << 5,
    SDWebImageHandleCookies = 1 << 6,
    SDWebImageAllowInvalidSSLCertificates = 1 << 7,
    SDWebImageHighPriority = 1 << 8,
    SDWebImageDelayPlaceholder = 1 << 9,
    SDWebImageTransformAnimatedImage = 1 << 10,
    SDWebImageAvoidAutoSetImage = 1 << 11,
    SDWebImageScaleDownLargeImages = 1 << 12
};

“<<”是位运算中的左移运算符
第一个值 SDWebImageRetryFailed = 1 << 0,十进制 1 转化为二进制为 0b00000001
这里 <<0 将所有二进制位左移0位,那么还是 0b00000001, 也就是 1
第二个枚举值SDWebImageLowPriority = 1 << 1
这里是将 1 的二进制所有位向左移动 1 位, 空缺的用 0 补齐
那么 0b00000001 变成 0b00000010,所以 SDWebImageLowPriority 十进制值为 2。

依次类推:
SDWebImageCacheMemoryOnly 向左移动 2 位就是 0b00000100 十进制值是 4,
SDWebImageProgressiveDownload 向左移动 3 位就是 0b00001000 十进制值是 8.

| 或运算

或运算作用是将两个数的相同位进行或运算
即如果两个对应位有一个位为 1,则运算后此位为 1,如果两个对应位都为 0, 则运算结果为 0
例如 0b00000001 | 0b00000010,结果为 0b00000011 十进制值为 3
下图示例:

又当 options 值为 SDWebImageRetryFailed | SDWebImageCacheMemoryOnly 时
执行或运算0b00000001| 0b00000100 = 0b00000101 十进制值是5

& 与运算

当对应位数同为 1 结果才为 1
例如 0b00000001& 0b00000010,结果为 0b00000000, 十进制值是 0.
0b00000011& 0b00000001,结果为 0b00000001, 十进制值是 1.

总结 :
SD 中的例子:

枚举传入多个值 做 | 运算
SDWebImageRetryFailed | SDWebImageCacheMemoryOnly 做或运算传入多个枚举值

   [customImageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRetryFailed | SDWebImageCacheMemoryOnly];

检测传入的枚举有没有某个值 做 & 运算
(options & SDWebImageRetryFailed) 就是判断 options 中有没有 SDWebImageRetryFailed 这个枚举
也就是客户端有没有传入的 options 是否包含 SDWebImageRetryFailed 这个枚举

    if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
    }


2> dispatch_semaphore_wait

SD 用到信号量的地方非常多
他定义了两个宏来使用信号量

#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);

举个例子 :
比如在单例 SDImageCache 中
初始化时创建一个值为 1 的信号量

self.weakCacheLock = dispatch_semaphore_create(1);

用的时候是这样 :

        LOCK(self.weakCacheLock);
        [self.weakCache setObject:obj forKey:key];
        UNLOCK(self.weakCacheLock);

逻辑是这样 :
假设代码小红执行到 LOCK(self.weakCacheLock);
由于信号量的值是 1 , 不需要等待
所以把值减 1 值变为 0, 继续往下执行
当还没有执行完 [self.weakCache setObject:obj forKey:key]; 的时候
恰好代码小白也执行到 LOCK(self.weakCacheLock);
但这个时候信号量值是 0, 所以要等待
等小红的 [self.weakCache setObject:obj forKey:key]; 执行结束
UNLOCK(self.weakCacheLock); 把信号量加 1
小白的等待才会结束
并把信号量减 1 继续往下执行
如果这时候有小蓝执行到 LOCK(self.weakCacheLock);
还是会等待小白把信号量加回 1 才能继续执行
这样就完成了同步操作


3>涉及的宏定义

3-1>FOUNDATION_EXPORT:

用来定义常量,和#define作用一样,只不过在检测字符串的值是否相等是比#define的效率更高,因为比较的是指针地址。

3-2>NS_DESIGNATED_INITIALIZER :

NS_DESIGNATED_INITIALIZER宏来实现指定构造器,通常是想告诉调用者要用这个方法去初始化类对象,便于规范API。

3-2>__deprecated_msg

用于提示此方法或属性已经废弃。

@property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility");
上一篇下一篇

猜你喜欢

热点阅读