使用方法
UIImageView *imageView;
NSURL *url = [NSURL URLWithString:@"https://www.jpg"];
[imageView sd_setImageWithURL:];
从对外使用函数开始
UIImageView分类中的函数
-sd_setImageWithURL:
该函数最终调用
-sd_setImageWithURL:placeholderImage:options:progress:completed:
类似的对外使用函数还有多个:
-sd_setImageWithURL:placeholderImage:
-sd_setImageWithURL:placeholderImage:options:
-sd_setImageWithURL:placeholderImage:options:completed:
等等,这些函数调用的都是同一个函数
-sd_setImageWithURL:placeholderImage:options:progress:completed:
而这个函数又是直接调用UIView分类中的函数
UIView -sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:
在UIView分类中,继续往下调用
-sd_internalSetImageWithURL:placeholderImage:options:operationKey:setImageBlock:progress:completed:context:
这个函数的实现以及说明如下
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
operationKey:(nullable NSString *)operationKey
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock
context:(nullable NSDictionary *)context {
// 通过唯一标识,取消之前的???
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
// 将请求的url保存(类似用runtime实现属性Property)
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// SDWebImageDelayPlaceholder代表延时使用placeholder, 判断条件的意思是不包含SDWebImageDelayPlaceholder,即使显示placeholder
if (!(options & SDWebImageDelayPlaceholder)) {
// dispatch_main_async_safe:如果当前在主线程,则直接执行block,否则异步执行dispatch_async
dispatch_main_async_safe(^{
[self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
});
}
if (url) {
#if SD_UIKIT
// check if activityView is enabled or not
if ([self sd_showActivityIndicatorView]) {
// 加载过程中显示菊花
[self sd_addActivityIndicator];
}
#endif
// reset the progress
// 重置下载进度
self.sd_imageProgress.totalUnitCount = 0;
self.sd_imageProgress.completedUnitCount = 0;
// image下载管理类
SDWebImageManager *manager;
if ([context valueForKey:SDWebImageExternalCustomManagerKey]) {
manager = (SDWebImageManager *)[context valueForKey:SDWebImageExternalCustomManagerKey];
} else {
manager = [SDWebImageManager sharedManager];
}
__weak __typeof(self)wself = self;
SDWebImageDownloaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
wself.sd_imageProgress.totalUnitCount = expectedSize;
wself.sd_imageProgress.completedUnitCount = receivedSize;
if (progressBlock) {
progressBlock(receivedSize, expectedSize, targetURL);
}
};
id operation = [manager loadImageWithURL:url options:options progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
__strong __typeof (wself) sself = wself;
if (!sself) { return; }
#if SD_UIKIT
[sself sd_removeActivityIndicator];
#endif
// if the progress not been updated, mark it to complete state
if (finished && !error && sself.sd_imageProgress.totalUnitCount == 0 && sself.sd_imageProgress.completedUnitCount == 0) {
sself.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown;
sself.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown;
}
BOOL shouldCallCompletedBlock = finished || (options & SDWebImageAvoidAutoSetImage);
BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) ||
(!image && !(options & SDWebImageDelayPlaceholder)));
SDWebImageNoParamsBlock callCompletedBlockClojure = ^{
if (!sself) { return; }
if (!shouldNotSetImage) {
[sself sd_setNeedsLayout];
}
if (completedBlock && shouldCallCompletedBlock) {
completedBlock(image, error, cacheType, url);
}
};
// case 1a: we got an image, but the SDWebImageAvoidAutoSetImage flag is set
// OR
// case 1b: we got no image and the SDWebImageDelayPlaceholder is not set
if (shouldNotSetImage) {
dispatch_main_async_safe(callCompletedBlockClojure);
return;
}
UIImage *targetImage = nil;
NSData *targetData = nil;
if (image) {
// case 2a: we got an image and the SDWebImageAvoidAutoSetImage is not set
targetImage = image;
targetData = data;
} else if (options & SDWebImageDelayPlaceholder) {
// case 2b: we got no image and the SDWebImageDelayPlaceholder flag is set
targetImage = placeholder;
targetData = nil;
}
#if SD_UIKIT || SD_MAC
// check whether we should use the image transition
SDWebImageTransition *transition = nil;
if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) {
transition = sself.sd_imageTransition;
}
#endif
dispatch_main_async_safe(^{
#if SD_UIKIT || SD_MAC
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
#else
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
#endif
callCompletedBlockClojure();
});
}];
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
} else {
dispatch_main_async_safe(^{
#if SD_UIKIT
[self sd_removeActivityIndicator];
#endif
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
}
图片下载类:SDWebImageDownloader