SDWebImage 360°无死角分析之整理
打算用几篇文章整理一下 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.
总结 :
-
:
|
或运算用来累加枚举值
例如SDWebImageRetryFailed | SDWebImageCacheMemoryOnly = 0b00000001| 0b00000100 = 0b00000101
值是 SDWebImageRetryFailed 和 SDWebImageCacheMemoryOnly 的集合 -
&
与运算用来检测是否含有某个枚举值
比如 SDWebImageRetryFailed 和 SDWebImageCacheMemoryOnly 的集合是 0b00000101
0b00000101 & 0b00000010 = 0
那么枚举中不含有 0b00000010 这个值
0b00000101 & 0b00000001 = 1
那么枚举中含有 0b00000001 这个值
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");