iOS SDWebImage详细介绍

article/2025/10/7 11:02:49

在iOS的图片加载框架中,SDWebImage使用频率非常高。它支持从网络中下载且缓存图片,并设置图片到对应的UIImageView控件或者UIButton控件。在项目中使用SDWebImage来管理图片加载相关操作可以极大地提高开发效率,让我们更加专注于业务逻辑实现。本文讲解的版本为4.4.2版本。

一、SDWebImage 概论

SDWebImage是个支持异步下载与缓存的UIImageView扩展。项目主要提供了一下功能:

1.提供了一个UIImageView的category用来加载网络图片并且对网络图片的缓存进行管理
2.采用异步方式来下载网络图片
3.采用异步方式,使用内存+磁盘来缓存网络图片,拥有自动的缓存过期处理机制。
4.支持GIF动画
5.支持WebP格式
6.同一个URL的网络图片不会被重复下载
7.失效,虚假的URL不会被无限重试
8.耗时操作都在子线程,确保不会阻塞主线程
9.使用GCD和ARC
10.支持Arm64
11.支持后台图片解压缩处理
12.项目支持的图片格式包括 PNG,JPEG,GIF,Webp等

二、SDWebImage组织架构

在这里插入图片描述

关键类讲解

SDWebImageDownloader: 负责维持图片的下载队列;
SDWebImageDownloaderOperation: 负责真正的图片下载请求;
SDImageCache: 负责图片的缓存;
SDWebImageManager: 是总的管理类,维护了一个SDWebImageDownloader实例和一个SDImageCache实例,是下载与缓存的桥梁;
SDWebImageDecoder: 负责图片的解压缩;
SDWebImagePrefetcher: 负责图片的预取;
UIImageView+WebCache: 和其他的扩展都是与用户直接打交道的。

其中,最重要的三个类就是SDWebImageDownloaderSDImageCacheSDWebImageManager。接下来我们就分别详细地研究一下这些类各自具体做了哪些事,又是怎么做的。

为了便于大家从宏观上有个把握,这里先给出项目的框架结构:

在这里插入图片描述

  • UIImageView+WebCacheUIButton+WebCache直接为表层的 UIKit框架提供接口
  • SDWebImageManger负责处理和协调SDWebImageDownloaderSDWebImageCache, 并与 UIKit层进行交互。
  • SDWebImageDownloaderOperation真正执行下载请求;最底层的两个类为高层抽象提供支持。

三、各个类详解

我们按照上图中从上到下执行的流程来研究各个类

3.1 UIImageView+WebCache

这里只用UIImageView+WebCache来举个例子,其他的扩展类似。

使用场景:已知图片的url地址,下载图片并设置到UIImageView上。

UIImageView+WebCache提供了一系列的接口:

- (void)sd_setImageWithURL:(nullable NSURL *)url;- (void)sd_setImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholder;- (void)sd_setImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholderoptions:(SDWebImageOptions)options;- (void)sd_setImageWithURL:(nullable NSURL *)urlcompleted:(nullable SDExternalCompletionBlock)completedBlock;- (void)sd_setImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholdercompleted:(nullable SDExternalCompletionBlock)completedBlock;- (void)sd_setImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholderoptions:(SDWebImageOptions)optionscompleted:(nullable SDExternalCompletionBlock)completedBlock;- (void)sd_setImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholderoptions:(SDWebImageOptions)optionsprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDExternalCompletionBlock)completedBlock;- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholderoptions:(SDWebImageOptions)optionsprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDExternalCompletionBlock)completedBlock;

这些接口最终都会调用

- (void)sd_setImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholderoptions:(SDWebImageOptions)optionsprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDExternalCompletionBlock)completedBlock;

新版本还给UIView增加了分类,即UIView+WebCache,最终上述方法会走到下面的方法去具体操作,比如下载图片等。

- (void)sd_internalSetImageWithURL:(nullable NSURL *)urlplaceholderImage:(nullable UIImage *)placeholderoptions:(SDWebImageOptions)optionsoperationKey:(nullable NSString *)operationKeysetImageBlock:(nullable SDSetImageBlock)setImageBlockprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDExternalCompletionBlock)completedBlockcontext:(nullable NSDictionary<NSString *, id> *)context;

接下来对该方法进行解析

  • 第一步:取消当前正在进行的异步下载,确保每个UIImageView对象中永远只存在一个operation,当前只允许一个图片网络请求,该operation负责从缓存中获取image或者是重新下载image。具体执行代码是:
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
// 取消先前下载的任务
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
... // 下载图片操作
// 将生成的加载操作赋值给UIView的自定义属性
[self sd_setImageLoadOperation:operation forKey:validOperationKey];

上述方法定义在UIView+WebCacheOperation类中

- (void)sd_setImageLoadOperation:(nullable id<SDWebImageOperation>)operation forKey:(nullable NSString *)key {if (key) {// 如果之前已经有过该图片的下载操作,则取消之前的图片下载操作[self sd_cancelImageLoadOperationWithKey:key];if (operation) {SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];@synchronized (self) {[operationDictionary setObject:operation forKey:key];}}}
}- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {if (key) {// Cancel in progress downloader from queueSDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; // 获取添加在UIView的自定义属性id<SDWebImageOperation> operation;@synchronized (self) {operation = [operationDictionary objectForKey:key];}if (operation) {// 实现了SDWebImageOperation的协议if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {[operation cancel];}@synchronized (self) {[operationDictionary removeObjectForKey:key];}}}
}

实际上,所有的操作都是由一个实际上,所有的操作都是由一个operationDictionary字典维护的,执行新的操作之前,cancel所有的operation

  • 第二步:占位图策略
    作为图片下载完成之前的替代图片。dispatch_main_async_safe是一个宏,保证在主线程安全执行。
if (!(options & SDWebImageDelayPlaceholder)) {dispatch_main_async_safe(^{// 设置占位图[self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];});
}
  • 第三步:判断url是否合法
    如果url合法,则进行图片下载操作,否则直接block回调失败
if (url) {// 下载图片操作
} else {dispatch_main_async_safe(^{
#if SD_UIKIT[self sd_removeActivityIndicator];
#endifif (completedBlock) {NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];completedBlock(nil, error, SDImageCacheTypeNone, url);}});
}
  • 第四步 下载图片操作
    下载图片的操作是由SDWebImageManager完成的,它是一个单例
- (id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)urloptions:(SDWebImageOptions)optionsprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDInternalCompletionBlock)completedBlock;

下载完成之后刷新UIImageView的图片。

// 根据枚举类型,判断是否需要设置图片
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);}
};if (shouldNotSetImage) {    // 不要自动设置图片,则调用block传入image对象dispatch_main_async_safe(callCompletedBlockClojure);return;
}// 设置图片操作
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];
#endifcallCompletedBlockClojure();
});

最后,把返回的id operation添加到operationDictionary中,方便后续的cancel

// 将生成的加载操作赋值给UIView的自定义属性
[self sd_setImageLoadOperation:operation forKey:validOperationKey];

3.2 SDWebImageManager

SDWebImageManager.h中是这样描述SDWebImageManager类的:

 /*** The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.* It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).* You can use this class directly to benefit from web image downloading with caching in another context than* a UIView.
*/

即隐藏在UIImageView+WebCache背后,用于处理异步下载和图片缓存的类,当然你也可以直接使用SDWebImageManager的方法 来直接下载图片。

- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)urloptions:(SDWebImageOptions)optionsprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDInternalCompletionBlock)completedBlock;

SDWebImageManager.h首先定义了一些枚举类型的SDWebImageOptions

然后,声明了四个block:

// 操作完成的回调,被上层的扩展调用。
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);// 被SDWebImageManager调用。
// 如果使用了SDWebImageProgressiveDownload标记,这个block可能会被重复调用,直到图片完全下载结束,
// finished=true,再最后调用一次这个block。
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);// SDWebImageManager每次把URL转换为cache key的时候调用,可以删除一些image URL中的动态部分。
typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL);

定义了SDWebImageManagerDelegate协议:

@protocol SDWebImageManagerDelegate @optional
// 控制在cache中没有找到image时 是否应该去下载。
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;// 在下载之后,缓存之前转换图片。在全局队列中操作,不阻塞主线程
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;@end

SDWebImageManager是单例使用的,分别维护了一个SDImageCache实例和一个SDWebImageDownloader实例。 对象方法分别是:

// 初始化SDWebImageManager单例,在init方法中已经初始化了cache单例和downloader单例。
- (instancetype)initWithCache:(SDImageCache *)cache downloader:(SDWebImageDownloader *)downloader;
// 下载图片
- (id )downloadImageWithURL:(NSURL *)urloptions:(SDWebImageOptions)optionsprogress:(SDWebImageDownloaderProgressBlock)progressBlockcompleted:(SDWebImageCompletionWithFinishedBlock)completedBlock;
// 缓存给定URL的图片
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;
// 取消当前所有的操作
- (void)cancelAll;
// 监测当前是否有进行中的操作
- (BOOL)isRunning;
// 监测图片是否在缓存中, 先在memory cache里面找  再到disk cache里面找
- (BOOL)cachedImageExistsForURL:(NSURL *)url;
// 监测图片是否缓存在disk里
- (BOOL)diskImageExistsForURL:(NSURL *)url;
// 监测图片是否在缓存中,监测结束后调用completionBlock
- (void)cachedImageExistsForURL:(NSURL *)urlcompletion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
// 监测图片是否缓存在disk里,监测结束后调用completionBlock
- (void)diskImageExistsForURL:(NSURL *)urlcompletion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
//返回给定URL的cache key
- (NSString *)cacheKeyForURL:(NSURL *)url;

我们主要研究

- (nullable id <SDWebImageOperation>)loadImageWithURL:(nullable NSURL *)urloptions:(SDWebImageOptions)optionsprogress:(nullable SDWebImageDownloaderProgressBlock)progressBlockcompleted:(nullable SDInternalCompletionBlock)completedBlock;

1.首先,监测url 的合法性:

if ([url isKindOfClass:NSString.class]) {url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {url = nil;
}

第一个判断条件是防止很多用户直接传递NSString作为NSURL导致的错误,第二个判断条件防止crash。

2.集合failedURLs保存之前失败的urls,如果url为空或者url之前失败过且不采用重试策略,直接调用completedBlock返回错误。

BOOL isFailedUrl = NO;
if (url) {  // 判断url是否是失败过的urlLOCK(self.failedURLsLock);isFailedUrl = [self.failedURLs containsObject:url];UNLOCK(self.failedURLsLock);
}
// 如果url为空或者url下载失败并且设置了不再重试
if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {[self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil] url:url];return operation;
}

3.保存操作

LOCK(self.runningOperationsLock);
[self.runningOperations addObject:operation];
UNLOCK(self.runningOperationsLock);

runningOperations是一个可变数组,保存所有的operation,主要用来监测是否有operation在执行,即判断running状态。

4.查找缓存
SDWebImageManager会首先在memory以及disk的cache中查找是否下载过相同的照片,即调用imageCache的下面方法

- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock;

如果操作取消,则直接返回

__strong __typeof(weakOperation) strongOperation = weakOperation;
if (!strongOperation || strongOperation.isCancelled) {  // operation取消,那么将下载任务从下载队列中直接移除[self safelyRemoveOperationFromRunning:strongOperation];return;
}

如果没有在缓存中找到图片,或者不管是否找到图片,只要operationSDWebImageRefreshCached标记,那么若SDWebImageManagerDelegateshouldDownloadImageForURL方法返回true,即允许下载时,都使用 imageDownloader的下载方法

- (id )downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock

如果下载有错误,直接调用completedBlock返回错误,并且视情况将url添加到failedURLs里面;

dispatch_main_sync_safe(^{if (strongOperation && !strongOperation.isCancelled) {completedBlock(nil, error, SDImageCacheTypeNone, finished, url);}
});if (error.code != NSURLErrorNotConnectedToInternet&& error.code != NSURLErrorCancelled&& error.code != NSURLErrorTimedOut&& error.code != NSURLErrorInternationalRoamingOff&& error.code != NSURLErrorDataNotAllowed&& error.code != NSURLErrorCannotFindHost&& error.code != NSURLErrorCannotConnectToHost) {@synchronized (self.failedURLs) {[self.failedURLs addObject:url];}
}

如果下载成功,若支持失败重试,将urlfailURLs里删除:

if ((options & SDWebImageRetryFailed)) {@synchronized (self.failedURLs) {[self.failedURLs removeObject:url];}
}

如果delegate实现了,imageManager:transformDownloadedImage:withURL:方法,图片在缓存之前,需要做转换(在全局队列中调用,不阻塞主线程)。转化成功切下载全部结束,图片存入缓存,调用completedBlock回调,第一个参数是转换后的image

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];if (transformedImage && finished) {BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];//将图片缓存起来[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk];}dispatch_main_sync_safe(^{if (strongOperation && !strongOperation.isCancelled) {completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);}});
});

否则,直接存入缓存,调用completedBlock回调,第一个参数是下载的原始image

if (downloadedImage && finished) {[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
}dispatch_main_sync_safe(^{if (strongOperation && !strongOperation.isCancelled) {completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);}
});

存入缓存都是调用imageCache的下面方法

- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk

如果没有在缓存找到图片,且不允许下载,直接调用completedBlock,第一个参数为nil

dispatch_main_sync_safe(^{__strong __typeof(weakOperation) strongOperation = weakOperation;if (strongOperation && !weakOperation.isCancelled) {//为啥这里用weakOperation TODOcompletedBlock(nil, nil, SDImageCacheTypeNone, YES, url);}
});

最后都要将这个operationrunningOperations里删除。

@synchronized (self.runningOperations) {[self.runningOperations removeObject:operation];}

3.3 SDWebImageCombinedOperation

@interface SDWebImageCombinedOperation : NSObject @property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
@property (strong, nonatomic) NSOperation *cacheOperation;@end

是一个遵循SDWebImageOperation协议的NSObject子类。

@protocol SDWebImageOperation - (void)cancel;@end

在里面封装一个NSOperation,这么做的目的应该是为了使代码更简洁。因为下载操作需要查询缓存的operation和实际下载的operation,这个类的cancel方法可以同时cancel两个operation,同时还可以维护一个状态cancelled

SDWebImage 使用

1.使用UIImageView+WebCache category来加载UITableViewcell的图片

[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://img1.cache.netease.com/catchpic/5/51/5132C377F99EEEE927697E62C26DDFB1.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

2.使用Blocks,采用这个方案可以在网络图片加载过程中得知图片的下载进度和图片加载成功与否

[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://img1.cache.netease.com/catchpic/5/51/5132C377F99EEEE927697E62C26DDFB1.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {// ... completion code here ... }];

3.使用SDWebImageManagerSDWebImageManagerUIImageView+WebCache category的实现提供接口。

SDWebImageManager *manager = [SDWebImageManager sharedManager] ;
[manager downloadImageWithURL:imageURL options:0 progress:^(NSInteger   receivedSize, NSInteger expectedSize) { // progression tracking code}  completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType,   BOOL finished, NSURL *imageURL) { if (image) { // do something with image}
}];

4.加载图片还有使用SDWebImageDownloaderSDImageCache方式

5.key的来源

// 利用Image的URL生成一个缓存时需要的key.
// 这里有两种情况,第一种是如果检测到cacheKeyFilter不为空时,利用cacheKeyFilter来处理URL生成一个key.
// 如果为空,那么直接返回URL的string内容,当做key.
- (NSString *)cacheKeyForURL:(NSURL *)url {if (self.cacheKeyFilter) {return self.cacheKeyFilter(url);}else {return [url absoluteString];}
}

SDWebImage 流程

在这里插入图片描述

SDWebImage 接口

SDWebImage是一个成熟而且比较庞大的框架,但是在使用过程中并不需要太多的接口,这算是一种代码封装程度的体现。这里就介绍比较常用的几个接口。

1.给UIImageView设置图片的接口,SDWebImage有提供多个给UIImageView设置图片的接口,最终所有的接口都会调用下图的这个接口,这是大多数框架的做法。

///所以设置图片的方法最终都会调用该方法
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
}

2.获取SDWebImage的磁盘缓存大小,在项目中有时候会需要统计应用的磁盘缓存内容大小,那么获取图片的缓存大小就是使用这个接口来实现

[SDImageCache sharedImageCache] getSize];

3.清理内存缓存,清理内存中缓存的图片资源,释放内存资源。

[[SDImageCache sharedImageCache] clearMemory];

4.有了清理内存缓存,自然也有清理磁盘缓存的接口

[[SDImageCache sharedImageCache] clearDisk];

SDWebImage 解析

<1>入口setImageWithURL:placeholderImage:options:会先把placeholderImage显示,然后 SDWebImageManager根据URL开始处理图片。

<2>进入SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache从缓存查找图片是否已经下载queryDiskCacheForKey:delegate:userInfo:

<3>先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate回调imageCache:didFindImage:forKey:userInfo:SDWebImageManager

<4>SDWebImageManagerDelegate回调webImageManager:didFinishWithImage:UIImageView+WebCache等前端展示图片。

<5>如果内存缓存中没有,生成NSInvocationOperation添加到队列开始从硬盘查找图片是否已经缓存。

<6>根据URLKey在硬盘缓存目录下尝试读取图片文件。这一步是在NSOperation进行的操作,所以回主线程进行结果回调notifyDelegate:

<7>如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate回调imageCache:didFindImage:forKey:userInfo:。进而回调展示图片。

<8>如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调imageCache:didNotFindImageForKey:userInfo:

<9>共享或重新生成一个下载器SDWebImageDownloader开始下载图片。

<10>图片下载由NSURLConnection来做,实现相关delegate来判断图片下载中、下载完成和下载失败。

<11>connection:didReceiveData:中利用ImageIO做了按图片下载进度加载效果。

<12>connectionDidFinishLoading:数据下载完成后交给SDWebImageDecoder做图片解码处理。

<13>图片解码处理在一个NSOperationQueue完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。

<14>在主线程notifyDelegateOnMainThreadWithInfo:宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给SDWebImageDownloader

<15>imageDownloader:didFinishWithImage:回调给SDWebImageManager告知图片下载完成。

<16>通知所有的downloadDelegates下载完成,回调给需要的地方展示图片。

<17>将图片保存到SDImageCache中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独NSInvocationOperation完成,避免拖慢主线程。

<18>SDImageCache在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。

<19>SDWebImage也提供了UIButton+WebCacheMKAnnotationView+WebCache,方便使用。

<20>SDWebImagePrefetcher可以预先下载图片,方便后续使用。

从上面流程可以看出,当你调用setImageWithURL:方法的时候,他会自动去给你干这么多事,当你需要在某一具体时刻做事情的时候,你可以覆盖这些方法。比如在下载某个图片的过程中要响应一个事件,就覆盖这个方法:

// 覆盖方法,指哪打哪,这个方法是下载imagePath2的时候响应
SDWebImageManager *manager = [SDWebImageManager sharedManager];[manager downloadImageWithURL:imagePath2 options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {NSLog(@"显示当前进度");
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {NSLog(@"下载完成");
}];

http://chatgpt.dhexx.cn/article/FjbNbIQr.shtml

相关文章

JNA入门

1&#xff0c;什么是JNA&#xff1f; JNA全称Java Native Access&#xff0c;是一个建立在JNI技术之上的Java开源框架。 2&#xff0c;JNA有什么用&#xff1f; Java开发过程中&#xff0c;有时候会需要和C&#xff0c;C等交互&#xff0c;JNA相当于中间的适配器 3&#xf…

JNA —— Java调用C/C++动态库

工作所需&#xff0c;要使用Java调用c/c的动态库&#xff0c;实现Java程序使用动态库中的函数。 搜索了一番&#xff0c;常用的有JNI、JNA方法。 JNI&#xff08;Java Native Interface&#xff09; JNI定义了一种公用的语法&#xff0c;当Java和c/c都遵循这样的语法时就可以互…

关于JAVA中的JNA

1、jna是什么 jna是java native access的简称&#xff0c;用他可以调用C、C代码&#xff0c;特别是windows中强大的库文件&#xff08;dll&#xff0c;在linux下是so文件&#xff09;&#xff0c;这样java就可以操控底层的一些东西&#xff0c;比如调用加密机、智能卡之类的 2、…

JNA与JNI谁更受青睐呢

JNA(Java Native Access)框架是一个开源的Java框架&#xff0c;是SUN公司主导开发的&#xff0c;建立在经典的JNI的基础之上的一个框架。非常强大、易用。其中JNA是对JNI的封装&#xff0c;能让java使用者更好的使用本地的动态库 一、JNA与JNI的比较 JNI: JNI允许Java代码和其…

JNA实战系列:第一个简单的JNA开发程序

文章目录 第一个简单的JNA的开发程序一、引入依赖包二、创建一个接口&#xff0c;继承Libary类三、在Java中使用dll中封装的方法总结:JNA中调用C、CDLL或者.so库中的函数的步骤总结:思考 第一个简单的JNA的开发程序 假如有一个helloworld.h和一个helloworld.dll文件&#xff0…

Java通过JNA调用so库 Linux环境

记录一下自己的JNA调研成果&#xff0c;需求是公司同事用C写了一个红外测温SDK&#xff0c;编译成so文件后提供给客户使用。客户需要一个Linux环境用Java调用so库的一个demo&#xff0c;刚好就我一个懂点Java&#xff0c;所有有了这次调研。 因为JNA相关资料实在太少&#xff…

JNI便捷开发框架JNA框架之入门(一)

一、JNA介绍 JNA(Java Native Access)框架是一个开源的Java框架&#xff0c;是SUN公司主导开发的&#xff0c;建立在经典的JNI的基础之上的一个框架。它提供一组Java工具类用于在运行期动态访问系统本地共享类库而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中…

JNA简介

2019独角兽企业重金招聘Python工程师标准>>> JNA JNA&#xff08;Java Native Access &#xff09;提供一组Java工具类用于在运行期动态访问系统本地库&#xff08;native library&#xff1a;如Window的dll&#xff09;而不需要编写任何Native/JNI代码。开发人员只…

JNA的概念

1. JNA简单介绍 先说JNI(Java Native Interface)吧&#xff0c;有过不同语言间通信经历的一般都知道&#xff0c;它允许Java代码和其他语言&#xff08;尤其C/C&#xff09;写的代码进行交互&#xff0c;只要遵守调用约定即可。首先看下JNI调用C/C的过程&#xff0c;注意写程序…

Java 之 JNA(调用第三方库)

是什么&#xff1f; 一、了解JNA之前&#xff0c;我们先了解一下JNA的前身JNI&#xff08;Java Native Interface&#xff09;&#xff1a;通过使用 Java本地接口书写程序&#xff0c;可以确保代码在不同的平台上方便移植。 [1] 从Java1.1开始&#xff0c;JNI标准成为java平台…

JNA实战笔记汇总(一)—— JNA简介及demo环境创建

目录 1、简介 2、原理 3、配置环境&#xff0c;创建demo 3.1 搞清楚.dll/.so文件适用环境 3.2 创建一个普通的maven项目 3.2.1 将.dll/.so文件放在resources根路径下 3.2.2 pom.xml文件添加jna依赖 3.2.3 编写一个CLibrary接口&#xff0c;继承Library接口 3.2.4 编写…

ROW(行)与COLUMN(列)

数列数&#xff0c;COLUMNS&#xff08;A:B&#xff09;2&#xff0c;即A到B一共两列。

column函数HTML5,column函数 excel中column函数的使用方法

column函数是一种查询的工具,我相信许多人都不会使用到这一个函数,因此在实际工程当中并不是十分的常见,然而这一款韩束如果能够掌握,对我们的工作也是非常有帮助的,接下来我们就一起来好好的了解一下这个函数究竟该如何使用。 column函数——column函数的使用方法 1.colu…

Duplicate column name ‘xxx_column‘

错误场景: 使用MyBatisPlus分页查询的情况下列名重复(注:select查询不报错, 映射正常) 例如 → select id, name, name from user 解决方法: 列名重复&#xff0c;删除重复的列名, 保证留一个就可以了 错误原因: 根据错误定位到PaginationInterceptor的queryTotal方法 最终…

mysql插入报错:colum xxx cannot be null

测试同学催促我赶紧解决上面的问题&#xff0c;首先看了下数据库这个字段确实是必填的&#xff0c;默认是当前时间 可是看了下代码发现mybatis的sql语句插入的时候包含了这个operate_time字段 那么讲道理必需给实体对象的operateTime字段赋值才行&#xff0c;可线上代码明明没有…

Vue template中函数获取el-table-colum中的属性值

方案如下&#xff1a; <el-table-column prop"id" label"操作"><template slot-scope"scope"><istyle"margin: 0 10px; cursor: pointer"click"clickItemInfo(scope.$index, scope.row,scope.column,scope.row.i…

hbase架构原理之region、memstore、hfile、hlog、columm-family、colum、cell

**鄙人的新书《elasticsearch7完全开发指南》&#xff0c;欢迎订阅&#xff01;** ----- https://wenku.baidu.com/view/8ff2ce94591b6bd97f192279168884868762b8e7 **《kibana权威指南》** ---- https://wenku.baidu.com/view/24cfee1ce43a580216fc700abb68a98270feac21 Hbas…

Row Column

Row Column 参考&#xff1a; Row classFlutter Layout Cheat SheetFlutter — Row/Column Cheat Sheet mainAxisAlignment和crossAxisAlignment 属性mainAxisAlignment和crossAxisAlignment mainAxisAlignment - 表示的是主轴的对齐方式crossAxisAlignment - 表示的是次轴…

Mybatis中resultMap的Colum和property属性

1&#xff1a; resultMap标签 当我们的数据库字段与实体类的属性不一致时&#xff0c;就需要使用该标签进行一一映射。 2&#xff1a;使用情况 2.1 简单查询 <resultMap id"这个resultMap的id" type"对应实体类的全限定类名"><id column"…

CSS3多列布局columns相关属性

tip&#xff1a;有问题或者需要大厂内推的我脉脉哦&#xff1a;丛培森 ٩( ‘ω’ )و CSS3中增加了可以实现多列布局的属性 在此之前的实现很麻烦可能需要各种定位 现在我们只需要一个属性就可以实现 多列布局类似于我们的报纸布局 这样可以方便读者观看 #多列数量与多列宽度#…