imageView sd_setImageWithURL 就能直接给imageVIew赋值图片 这个框架的核心类是SDWebImageManager 在外头面 UIImageView+webCache和 UIButton+webCache为下载提供接口。内部有SDWebimageManager 处理协调SDWebImageDownloader和SDWebImageCache SDWebImageDownloader负责处理下载任务 SDWebImageCache负责缓存的工作,添加,删除 查询缓存
UI层主要提供 操作接口
// ============== UIView+ WebCache.m ============== //
//valid key:UIImageView || UIButton
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
//UIView+WebCacheOperation 的 operationDictionary
//下面这行代码是保证没有当前正在进行的异步下载操作, 使它不会与即将进行的操作发生冲突
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
//添加临时的占位图(在不延迟添加占位图的option下)
if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
[self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
});
}
//如果url存在
if (url) {
...
__weak __typeof(self)wself = self;
//SDWebImageManager下载图片
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
...
//dispatch_main_sync_safe : 保证block能在主线程进行
dispatch_main_async_safe(^{
if (!sself) {
return;
}
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) {
//image,而且不自动替换 placeholder image
completedBlock(image, error, cacheType, url);
return;
} else if (image) {
//存在image,需要马上替换 placeholder image
[sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setNeedsLayout];
} else {
//没有image,在图片下载完之后显示 placeholder image
if ((options & SDWebImageDelayPlaceholder)) {
[sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setNeedsLayout];
}
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
//在操作缓存字典(operationDictionary)里添加operation,表示当前的操作正在进行
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
} else {
//如果url不存在,就在completedBlock里传入error(url为空)
dispatch_main_async_safe(^{
[self sd_removeActivityIndicator];
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
看一下SDImageCache和 SDWebImageDownder
// ============== SDImageCache.m ============== //
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock {
if (!key) {
if (doneBlock) {
doneBlock(nil, nil, SDImageCacheTypeNone);
}
return nil;
}
//================查看内存的缓存=================//
UIImage *image = [self imageFromMemoryCacheForKey:key];
// 如果存在,直接调用block,将image,data,CaheType传进去
if (image) {
NSData *diskData = nil;
//如果是gif,就拿到data,后面要传到doneBlock里。不是gif就传nil
if ([image isGIF]) {
diskData = [self diskImageDataBySearchingAllPathsForKey:key];
}
if (doneBlock) {
doneBlock(image, diskData, SDImageCacheTypeMemory);
}
//因为图片有缓存可供使用,所以不用实例化NSOperation,直接范围nil
return nil;
}
//================查看磁盘的缓存=================//
NSOperation *operation = [NSOperation new];
//唯一的子线程:self.ioQueue
dispatch_async(self.ioQueue, ^{
if (operation.isCancelled) {
// 在用之前就判断operation是否被取消了,作者考虑的非常严谨
return;
}
@autoreleasepool {
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
UIImage *diskImage = [self diskImageForKey:key];
if (diskImage && self.config.shouldCacheImagesInMemory) {
// cost 被用来计算缓存中所有对象的代价。当内存受限或者所有缓存对象的总代价超过了最大允许的值时,缓存会移除其中的一些对象。
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;
}