SDWebImage已经在iOS开发中被广泛使用,提供了UIImageView和UIButton的分类,解决了需要从网络上加载图片的烦恼。SDWebImage的强大之处不仅在于提供图片的下载,还提供了图片的解码,超大图片的按比例解码,图片的缓存及内存占用超额的清理等功能!
流程图
上面是SDWebImage主要对图片下载、处理、解压、存储等功能的主要类功能分布,接下来我们来依次解析每个步骤的功能!!
功能
我们接下来按照框架中的功能步骤来一步一步解析代码,我们会依次从主调用函数、查询内存或磁盘中的图片、下载图片、解压图片、存储图片、清理缓存等来展开讲解!!
- 主调用函数(UIKit层)
- (void)sd_setImageWithURL:(nullable NSURL *)url;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options;
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
/** 这些函数底层都是调用了 UIView+WebCache 类方法 **/
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
operationKey:(nullable NSString *)operationKey
internalSetImageBlock:(nullable SDInternalSetImageBlock)setImageBlock
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock
context:(nullable NSDictionary<NSString *, id> *)context;
sd_internalSetImageWithURL解析:
- 根据operationKey判断当前是否有相同的下载队列,有的话则取消;
- 若设置了placeholder占位图,则在主线程先显示占位图片;
- 判断是否需要显示菊花加载view,需要则加上;
- 查询加载图片,调用函数到内存或磁盘中是否有当前图片的存在;
- 查询内存中的图片
1、NSCache
NSCache
是一个类似NSDictionary
一个可变的集合;- 提供了可设置缓存的数目与内存大小限制的方式;
- 保证了处理的数据的线程安全性;
- 缓存使用的key不需要是实现
NSCopying
的类; - 当内存警告时内部自动清理部分缓存数据;
@property (strong, nonatomic, nonnull) SDMemoryCache *memCache;
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
// 将图片保存到Cache中
if (self.config.shouldCacheImagesInMemory) {
NSUInteger cost = image.sd_memoryCost;
[self.memCache setObject:image forKey:key cost:cost];
}
}
// setter方法设置大小,个数限制等
- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost {
self.memCache.totalCostLimit = maxMemoryCost;
}
- (NSUInteger)maxMemoryCost {
return self.memCache.totalCostLimit;
}
- (NSUInteger)maxMemoryCountLimit {
return self.memCache.countLimit;
}
- (void)setMaxMemoryCountLimit:(NSUInteger)maxCountLimit {
self.memCache.countLimit = maxCountLimit;
}
2、weakCache(NSMapTable)
- 由于NSCache内存自动清理机制有可能会出现存储资源太多导致某些资源被内存释放;
- weakCache是NSMapTable类型,用法与类似
NSDictionary,而且可以设置key与value的
NSPointerFunctionsOptions类型,方便存储;
- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g {
[self.weakCache setObject:obj forKey:[[key mutableCopy] copy]];
}
- (id)objectForKey:(id)key {
id obj = [self.weakCache objectForKey:key];
return obj;
}
当从内存中去查找缓存的图片时,会用图片的key去memCache中查找,若查找到内存中存在图片,则返回给用户回调使用;若未查找到图片,则进行接下来的步骤,从磁盘中读取!
- 查询磁盘中的图片
- (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key {
// 拼接存储在磁盘中的路径
NSString *defaultPath = [self defaultCachePathForKey:key];
NSData *data = [NSData dataWithContentsOfFile:defaultPath options:self.config.diskCacheReadingOptions error:nil];
if (data) {
return data;
}
// 去除stringByDeletingPathExtension扩展名的路径
data = [NSData dataWithContentsOfFile:defaultPath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil];
if (data) {
return data;
}
// 在自定义的customPaths路径中查找
NSArray<NSString *> *customPaths = [self.customPaths copy];
for (NSString *path in customPaths) {
NSString *filePath = [self cachePathForKey:key inPath:path];
NSData *imageData = [NSData dataWithContentsOfFile:filePath options:self.config.diskCacheReadingOptions error:nil];
if (imageData) {
return imageData;
}
imageData = [NSData dataWith