汇总记录:
本文基于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进行下载,逻辑不复杂,详细的参考源码
网友评论