读 SDWebImage 六 (编码器三:SDWebImageCodersManager)
2018-10-18 20:48:55 # SDWebImage

声明属性和方法

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;
}