美文网首页
SD一点小体会

SD一点小体会

作者: f0b693d9893e | 来源:发表于2020-04-01 17:59 被阅读0次

汇总记录:

本文基于SDWebImage 4.2.3版本进行分析和整理。

SDWebImage

|----SDWebImageCompat处理不同平台(iOS、TV、OS、Watch)宏,以及根据文件名@2x、@3x进行图片处理和缩放

|----SDWebImageOperation.h添加cancel的delegate

+----Cache

|--------SDImageCache主要处理缓存逻辑,重点集中在:NSCache(Memory)、Disk读写、清理Old File

|--------SDImageCacheConfig配置缓存参数:是否压缩、iCloud、InMemory、ReadingOption、时间和CacheSize

+----Downloader

|--------SDWebImageDownloaderOperation主要提供下载的Operation操作

|--------SDWebImageDownloader提供下载管理入口

+----Utils

|--------SDWebImageManager提供外层管理cache和download入口

|--------SDWebImagePrefetcher预处理获取Image,主要应用预加载的地方

+----Categories

|--------NSData+ImageContentType提供类型判断和ImageIO类型转换

|--------UIImage+GIFData转UIImage(GIF)扩展

|--------UIImage+MultiFormat提供BitMap或者未知类型的Data转UIImage扩展

|--------UIImage+WebPData转WebP扩展

|--------UIImage+ForceDecode解压操作

|--------UIView+WebCacheOperation提供顶层关于取消和下载记录的扩展

+----Decoder

|--------SDWebImageCodersManager整体Coders的入口,提供是否可Coder和Coder转发

|--------SDWebImageCoder主要说明Coder Delegate 需要实现的接口

|--------SDWebImageImageIOCoderPNG/JPEG的Encode和解压操作

|--------SDWebImageGIFCoderGIF的Coder操作

|--------SDWebImageWebPCoderWebP的Coder操作

|--------SDWebImageFrame辅助类,主要在GIF等动态图使用

|--------SDWebImageCoderHelper辅助类,包括方向、Gif图合成等

整体组件结构

sd结构

整体框架结构比较清晰,因为Decoder部分相对比较独立,业务逻辑处理主要在Cache、Downloader层级以及以上。

下文会以Cache、Downloader进行分解。


1、缓存部分解析

缓存部分逻辑主要是在SDImageCache,包括如下几个方面:

新增

删除

查询

缓存管理(过期)

SDWebImage的缓存中,主要走了一套NSCache管理内存和根据传入的Key转换MD5作为文件名存储。以及创建了一个IO操作的Queue进行管理IO操作。

这里重点注意,任何耗时:包括IO读写、转码等操作,都不应该放到主线程里面使用。

缓存部分其他地方都比较简单易懂,直接看源码即可。

重点说下如下两个值得学习的地方:

1、通过NSOperation管理queue任务

- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock {

    if (!key) {

        if (doneBlock) {

            doneBlock(nil, nil, SDImageCacheTypeNone);

        }

        return nil;

    }

    // First check the in-memory cache...

    UIImage *image = [self imageFromMemoryCacheForKey:key];

    if (image) {

        NSData *diskData = nil;

        if (image.images) {

            diskData = [self diskImageDataBySearchingAllPathsForKey:key];

        }

        if (doneBlock) {

            doneBlock(image, diskData, SDImageCacheTypeMemory);

        }

        return nil;

    }

    NSOperation *operation = [NSOperation new];

    dispatch_async(self.ioQueue, ^{

        if (operation.isCancelled) {

            // do not call the completion if cancelled

            return;

        }

        @autoreleasepool {

            NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];

            UIImage *diskImage = [self diskImageForKey:key];

            if (diskImage && self.config.shouldCacheImagesInMemory) {

                NSUInteger cost = SDCacheCostForImage(diskImage);

                [self.memCache setObject:diskImage forKey:key cost:cost];

            }

            if (doneBlock) {

                dispatch_async(dispatch_get_main_queue(), ^{

                    doneBlock(diskImage, diskData, SDImageCacheTypeDisk);

                });

            }

        }

    });

    return operation;

}

查询缓存的时候,这里采用了NSOperation进行是否取消的操作,因为当下载/缓存内容过多时,毕定存在先后处理顺序的问题,这时候可能由于用户操作等需要取消当前缓存处理,那么NSOperation这里起的唯一作用就是提供取消操作。可以参考具体的Manager里面缓存调起逻辑

2、申请系统后台时间处理任务

-(void)backgroundDeleteOldFiles{Class UIApplicationClass=NSClassFromString(@"UIApplication");if(!UIApplicationClass||![UIApplicationClass respondsToSelector:@selector(sharedApplication)]){return;}UIApplication*application=[UIApplication performSelector:@selector(sharedApplication)];__block UIBackgroundTaskIdentifier bgTask=[application beginBackgroundTaskWithExpirationHandler:^{// Clean up any unfinished task business by marking where you// stopped or ending the task outright.[application endBackgroundTask:bgTask];bgTask=UIBackgroundTaskInvalid;}];// Start the long-running task and return immediately.[selfdeleteOldFilesWithCompletionBlock:^{[application endBackgroundTask:bgTask];bgTask=UIBackgroundTaskInvalid;}];}

这里有个疑问点要注意,为啥会存在前后两部分都去释放Task任务。

iOS的后台任务有个背景,不管任何时候,都需要手动去调用endBackgroundTask结束后台任务,其实开启一个后台job的时候,因为时长有限,所以会存在两种结局:

在允许的时间内执行完成

规定时间内未执行完成

如上两种情况,在结束后都必须手动调用endBackgroundTask:

2、下载器(Downloader)

下载部分,主要是提供了一个Operation和一个Manager,其中SDWebImageDownloaderOperation里面提供了常用的Operation操作,也支持自定义的下载逻辑(实现SDWebImageDownloaderOperationInterface即可)。

2.1 SDWebImageDownloaderOperation 逻辑

该文件里面重点是Delegate:SDWebImageDownloaderOperationInterface的设计和一种实现方式SDWebImageDownloaderOperation(PS:优秀的开源库基本都会设计一套接口,再做一套基础的实现)。

// 这里描述写的很清楚,如果需要自定义的Downloader op,那么需要继承NSOperation并且实现SDWebImageDownloaderOperation

/**

Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol

*/

@protocol SDWebImageDownloaderOperationInterface<NSObject>

- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request

                              inSession:(nullable NSURLSession *)session

                                options:(SDWebImageDownloaderOptions)options;

- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock

                            completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;

- (BOOL)shouldDecompressImages;

- (void)setShouldDecompressImages:(BOOL)value;

- (nullable NSURLCredential *)credential;

- (void)setCredential:(nullable NSURLCredential *)value;

@end

SDWebImageDownloaderOperation主要是提供内置的下载实现,重点是使用NSURLSessionTask进行下载,逻辑不复杂,详细的参考源码

相关文章

网友评论

      本文标题:SD一点小体会

      本文链接:https://www.haomeiwen.com/subject/ipbauhtx.html