原始碼閱讀:SDWebImage(九)——SDWebImageCodersManager

堯少羽發表於2018-06-22

該文章閱讀的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

相關文章