SDWebImage 内部实现了一个图片解码/编码的图片编解码器,用于图片的编解码、压缩。其中涉及到编解码管理(SDWebImageCodersManager)、编解码协议(SDWebImageCoder)、PNG/JPEG/TIFF编解码,解压缩,显示大图(SDWebImageImageIOCoder)、GIF编解码(SDWebImageGIFCoder)、WebP编解码(SDWebImageWebPCoder)以及辅助类(SDWebImageCoderHelper

编解码管理( SDWebImageCodersManager

编解码管理器,整体编解码器的入口,该类遵守了 SDWebImageCoder 协议,说明这个类可以提供基本的编解码功能 。编解码器数组是一个优先级队列,也意味着处理多个图片编解码任务时新添加的编解码器将具有最高优先级(即被先调用)

声明属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
单例初始化
*/
+ (nonnull instancetype)sharedInstance;

/**
所有的编解码器都在这个编解码器管理中(编码器数组)这个编解码器数组是一个优先级对列, 这意味着最后添加的编解码器拥有最高的优先级
*/
@property (nonatomic, copy, readwrite, nullable) NSArray<id<SDWebImageCoder>> *coders;

/**
在编解码器数组的末尾添加一个新的编解码器。 新添加的编解码器优先级最高。

@param coder 需添加的coder
*/
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder;

/**
在编解码器数组中移除编码器

@param coder 需移除的coder
*/
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder;

初始化方法实现

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//单例
+ (nonnull instancetype)sharedInstance {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}

- (instancetype)init {
if (self = [super init]) {
// 初始化默认的编解码器,默认编码器只有SDWebImageImageIOCoder类型的
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy];
#ifdef SD_WEBP
//如果是WEBP,就添加SDWebImageWebPCoder单例
[mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]];
#endif
_coders = [mutableCoders copy];
_codersLock = dispatch_semaphore_create(1);
}
return self;
}

编码器IO操作

添加编码器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder {
//判断要添加的编解码器是否遵守SDWebImageCoder协议,以提供最基本的编解码功能
//如果不遵守SDWebImageCoder协议,返回
if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
return;
}
LOCK(self.codersLock);
//临时变量,编解码器数组,如果不存在,重新初始化一个
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [self.coders mutableCopy];
if (!mutableCoders) {
mutableCoders = [NSMutableArray array];
}
//添加新的coder
[mutableCoders addObject:coder];
//重新赋值给self.coders
self.coders = [mutableCoders copy];
UNLOCK(self.codersLock);
}

移除编码器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder {
//判断要添加的编解码器是否遵守SDWebImageCoder协议,以提供最基本的编解码功能
//如果不遵守SDWebImageCoder协议,返回
if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
return;
}
LOCK(self.codersLock);
//临时变量,编解码器数组,使其等于self.coders(深拷贝)
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [self.coders mutableCopy];
//移除编解码器coder
[mutableCoders removeObject:coder];
//重新赋值给self.coders
self.coders = [mutableCoders copy];
UNLOCK(self.codersLock);
}

SDWebImageCoder协议方法实现

解码协议实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
如果此编解码器可以解码某些data,返回YES,否则,它应该传递给另一个编码器

@param data 需要解码的图片数据
@return 如果此编解码器可以解码图片数据,返回YES,否则返回NO
*/
- (BOOL)canDecodeFromData:(NSData *)data {
LOCK(self.codersLock);
//临时变量,编解码器数组,赋值等于 self.coders
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
//倒序遍历编解码器数组(倒序的原因是:编解码器数组中最新添加的具有最高优先级)
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
//判断,如果其中有编解码器能够解码,就返回YES,否则返回NO
if ([coder canDecodeFromData:data]) {
return YES;
}
}
return NO;
}

/**
将图片数据解码为图片。

@param data 需要解码的图片数据
@return 解码后得到的图片
*/
- (UIImage *)decodedImageWithData:(NSData *)data {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
//倒序遍历编解码器列表
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
//判断,如果其中有编解码器能够解码,就执行解码操作,否则返回Image为nil
if ([coder canDecodeFromData:data]) {
return [coder decodedImageWithData:data];
}
}
return nil;
}

/**
使用原始图片和图片数据解压缩图片。

@param image 需要压缩的原图片
@param data 指向原始图像数据的指针。 指针本身是非空的,但图像数据可以为空。 如果需要,此数据将设置为缓存。 如果您不需要同时修改数据,请忽略此参数。
@param optionsDict 一个包含任何解压缩选项的字典。 通过{SDWebImageCoderScaleDownLargeImagesKey:@(YES)}缩小大图像
@return 解压缩后的图片
*/
- (UIImage *)decompressedImageWithImage:(UIImage *)image
data:(NSData *__autoreleasing _Nullable *)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
//如果image不存在,返回nil
if (!image) {
return nil;
}
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
//倒序遍历编解码器列表
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
//如果其中有编解码器可以解码,执行解压缩图片操作,并返回解压缩后的图片
if ([coder canDecodeFromData:*data]) {
//解压缩图片操作
UIImage *decompressedImage = [coder decompressedImageWithImage:image data:data options:optionsDict];
decompressedImage.sd_imageFormat = image.sd_imageFormat;
return decompressedImage;
}
}
return nil;
}

编码协议实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
如果此编码器可以编码某些图片格式,返回YES,否则,它应该传递给另一个编码器

@param format 图片格式
@return 如果此编码器可以编码图片格式,返回YES,否则返回NO
*/
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
//倒序遍历编解码器列表
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
//判断,如果其中有编解码器能够编码图片格式,就返回YES,否则返回NO
if ([coder canEncodeToFormat:format]) {
return YES;
}
}
return NO;
}

/**
将图片编码为图片数据(imagedata)

@param image 需要编码的图片
@param format 要编码的图片格式, 也有可能是 `SDImageFormatUndefined` 格式(未识别格式)
@return The encoded image data
*/
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
//如果image不存在,返回nil
if (!image) {
return nil;
}
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
//倒序遍历编解码器列表
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
//判断,如果其中有编解码器能够编码图片格式,就执行将图片以format格式编码为data操作,并返回imagedata
if ([coder canEncodeToFormat:format]) {
// 将图片编码为图片数据(imagedata)
return [coder encodedDataWithImage:image format:format];
}
}
return nil;
}