源码阅读:SDWebImage(九)——SDWebImageCodersManager

833 阅读3分钟

该文章阅读的SDWebImage的版本为4.3.3。

这个类遵守了SDWebImageCoder协议,意味着这个类可以提供基本的编解码功能。

1.公共属性

/**
 这个属性中保存着各种类型的编解码器
 */
@property (nonatomic, strong, readwrite, nullable) NSArray<SDWebImageCoder>* coders;

2.公共方法

/**
 添加编解码器
 */
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder;
/**
 移除编辑吗器
 */
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder;

3.私有属性

/**
 保存该类管理的所有编解码器
 */
@property (strong, nonatomic, nonnull) NSMutableArray<SDWebImageCoder>* mutableCoders;
/**
 操作编解码器数组的队列
 */
@property (strong, nonatomic, nullable) dispatch_queue_t mutableCodersAccessQueue;

4.公共方法的实现

+ (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类型的
        _mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy];
#ifdef SD_WEBP
        [_mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]];
#endif
        // 创建一个并发队列用于管理编解码器数组
        _mutableCodersAccessQueue = dispatch_queue_create("com.hackemist.SDWebImageCodersManager", DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

- (void)addCoder:(nonnull id<SDWebImageCoder>)coder {
    // 判断要添加的编解码器是否遵守了SDWebImageCoder协议,以提供最基本的编解码功能
    if ([coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
        // 利用GCD的栅栏功能保证数组在“写”的时候线程的安全
        dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
            // 保存编解码器
            [self.mutableCoders addObject:coder];
        });
    }
}

- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder {
    // 利用GCD的栅栏功能保证数组在“写”的时候线程的安全
    dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
        // 移除编解码器
        [self.mutableCoders removeObject:coder];
    });
}

5. 公共属性的读写方法

- (NSArray<SDWebImageCoder> *)coders {
    // 创建变量保存编解码器数组
    __block NSArray<SDWebImageCoder> *sortedCoders = nil;
    // 自定义并发队列同步执行
    dispatch_sync(self.mutableCodersAccessQueue, ^{
        // 获取保存编解码器数组数组的倒序数组
        sortedCoders = (NSArray<SDWebImageCoder> *)[[[self.mutableCoders copy] reverseObjectEnumerator] allObjects];
    });
    // 返回编解码器数组
    return sortedCoders;
}

- (void)setCoders:(NSArray<SDWebImageCoder> *)coders {
    // 利用GCD的栅栏功能保证数组在“写”的时候线程的安全
    dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
        // 直接保存
        self.mutableCoders = [coders mutableCopy];
    });
}

6.SDWebImageCoder协议方法的实现

  • 解码
- (BOOL)canDecodeFromData:(NSData *)data {
    // 遍历编解码器数组
    for (id<SDWebImageCoder> coder in self.coders) {
        // 如果其中有解码器能解码
        if ([coder canDecodeFromData:data]) {
            // 就返回YES
            return YES;
        }
    }
    return NO;
}
- (UIImage *)decodedImageWithData:(NSData *)data {
    // 如果没有数据就返回空
    if (!data) {
        return nil;
    }
    // 遍历编解码器数组
    for (id<SDWebImageCoder> coder in self.coders) {
        // 如果其中有解码器能解码
        if ([coder canDecodeFromData:data]) {
            // 调用解码器解码并返回
            return [coder decodedImageWithData:data];
        }
    }
    return nil;
}
- (UIImage *)decompressedImageWithImage:(UIImage *)image
                                   data:(NSData *__autoreleasing  _Nullable *)data
                                options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
    // 如果没有图片对象就不压缩了返回空
    if (!image) {
        return nil;
    }
    // 遍历编解码器数组
    for (id<SDWebImageCoder> coder in self.coders) {
        // 如果其中有解码器能解码
        if ([coder canDecodeFromData:*data]) {
            // 调用解码器压缩并返回
            return [coder decompressedImageWithImage:image data:data options:optionsDict];
        }
    }
    return nil;
}
  • 编码
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
    // 遍历编解码器数组
    for (id<SDWebImageCoder> coder in self.coders) {
        // 如果其中有编解码器能编码
        if ([coder canEncodeToFormat:format]) {
            // 就返回YES
            return YES;
        }
    }
    return NO;
}
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
    // 如果没有图片对象就返回空
    if (!image) {
        return nil;
    }
    // 遍历编解码器数组
    for (id<SDWebImageCoder> coder in self.coders) {
        // 如果其中有解码器能编码
        if ([coder canEncodeToFormat:format]) {
            // 调用编解码器编码并返回
            return [coder encodedDataWithImage:image format:format];
        }
    }
    return nil;
}

7.总结

这个是是编解码器的管理类,管理着用于图像编解码的类,默认只有SDWebImageImageIOCoder这个类,如果导入了WebP,默认就会还有SDWebImageWebPCoder类。

调用编解码器的顺序是后添加到数组的先调用,保证了用户如果自定义了编解码器,添加到该类后会被先调用。

源码阅读系列:SDWebImage

源码阅读:SDWebImage(一)——从使用入手

源码阅读:SDWebImage(二)——SDWebImageCompat

源码阅读:SDWebImage(三)——NSData+ImageContentType

源码阅读:SDWebImage(四)——SDWebImageCoder

源码阅读:SDWebImage(五)——SDWebImageFrame

源码阅读:SDWebImage(六)——SDWebImageCoderHelper

源码阅读:SDWebImage(七)——SDWebImageImageIOCoder

源码阅读:SDWebImage(八)——SDWebImageGIFCoder

源码阅读:SDWebImage(九)——SDWebImageCodersManager

源码阅读:SDWebImage(十)——SDImageCacheConfig

源码阅读:SDWebImage(十一)——SDImageCache

源码阅读:SDWebImage(十二)——SDWebImageDownloaderOperation

源码阅读:SDWebImage(十三)——SDWebImageDownloader

源码阅读:SDWebImage(十四)——SDWebImageManager

源码阅读:SDWebImage(十五)——SDWebImagePrefetcher

源码阅读:SDWebImage(十六)——SDWebImageTransition

源码阅读:SDWebImage(十七)——UIView+WebCacheOperation

源码阅读:SDWebImage(十八)——UIView+WebCache

源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat

源码阅读:SDWebImage(二十)——UIButton+WebCache

源码阅读:SDWebImage(二十一)——UIImageView+WebCache/UIImageView+HighlightedWebCache