SDWebImageManager主要关联SDWebImageDownloader和SDImageCache操作,即异步下载图片后进行缓存处理。
SDWebImageOptions说明:
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #1d9421}p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; min-height: 16.0px}p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #c91b13}p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo}p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px 'PingFang SC'; color: #1d9421}p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #c32275}span.s1 {font-variant-ligatures: no-common-ligatures}span.s2 {font-variant-ligatures: no-common-ligatures; color: #822e0e}span.s3 {font-variant-ligatures: no-common-ligatures; color: #c32275}span.s4 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures}span.s5 {font-variant-ligatures: no-common-ligatures; color: #000000}span.s6 {font: 14.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures}span.s7 {font-variant-ligatures: no-common-ligatures; color: #c91b13}span.s8 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures; color: #000000}span.s9 {font-variant-ligatures: no-common-ligatures; color: #0435ff}span.s10 {font-variant-ligatures: no-common-ligatures; color: #1d9421}span.s11 {font: 14.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures; color: #1d9421}
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageManager.h"
#import <objc/message.h>
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
// 是否取消当前所有操作
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
// 没有参数取消回调
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
// 执行缓存的操作
@property (strong, nonatomic) NSOperation *cacheOperation;
@end
@interface SDWebImageManager ()
// 图片缓存对象
@property (strong, nonatomic, readwrite) SDImageCache *imageCache;
// 图片下载对象
@property (strong, nonatomic, readwrite) SDWebImageDownloader *imageDownloader;
// 下载失败的图片URL
@property (strong, nonatomic) NSMutableSet *failedURLs;
// 装载正在执行操作的数组
@property (strong, nonatomic) NSMutableArray *runningOperations;
@end
@implementation SDWebImageManager
/**
* 生成一个SDWebImagemanager的单例
*
* @return <#return value description#>
*/
+ (id)sharedManager {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
/**
* 初始化SDImageCache、SDWebImageDownloader
*
* @return <#return value description#>
*/
- (instancetype)init {
SDImageCache *cache = [SDImageCache sharedImageCache];
SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader];
return [self initWithCache:cache downloader:downloader];
}
/**
* 初始化SDImageCache、SDWebImageDownloader
*
* @return <#return value description#>
*/
- (instancetype)initWithCache:(SDImageCache *)cache downloader:(SDWebImageDownloader *)downloader {
if ((self = [super init])) {
_imageCache = cache;
_imageDownloader = downloader;
_failedURLs = [NSMutableSet new];
_runningOperations = [NSMutableArray new];
}
return self;
}
/**
* 根绝URL获取缓存中的key
*
* @param url 图片URL
*
* @return 图片在缓存中对应的Key
*/
- (NSString *)cacheKeyForURL:(NSURL *)url {
if (!url) {
return @"";
}
if (self.cacheKeyFilter) {
return self.cacheKeyFilter(url);
} else {
return [url absoluteString];
}
}
/**
* 根据URL判断缓存中是否存在图片:先判断内存缓存、在判断磁盘缓存
*
* @param url 图片URL
*
* @return 是否存在图片
*/
- (BOOL)cachedImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
return [self.imageCache diskImageExistsWithKey:key];
}
/**
* 根据URL判断磁盘缓存中是否存在图片
*
* @param url 图片URL
*
* @return 是否存在图片
*/
- (BOOL)diskImageExistsForURL:(NSURL *)url {
NSString *key = [self cacheKeyForURL:url];
return [self.imageCache diskImageExistsWithKey:key];
}
/**
* 根据URL判断缓存中是否存在图片并进行回调:先判断内存缓存、在判断磁盘缓存
*
* @param url 图片URL
* @param completionBlock 图片在缓存中是否存在回调
*/
- (void)cachedImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
if (isInMemoryCache) {
// 确保回调在主线程中执行:making sure we call the completion block on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(YES);
}
});
return;
}
// 该方法的回调已在主线程中执行
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
/**
* 根据URL判断磁盘缓存中是否存在图片并进行回调
*
* @param url 图片URL
* @param completionBlock 图片在缓存中是否存在回调
*/
- (void)diskImageExistsForURL:(NSURL *)url
completion:(SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
/**
* 根据URL下载图片
*
* @param url 图片URL
* @param options 下载图片选项:SDWebImageOptions
* @param progressBlock 图片下载进度回调
* @param completedBlock 图片下载完成回调
*
* @return SDWebImageOperation
*/
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock {
// completedBlock为空时,断言将被执行,程序Crash,并打印出断言中的描述信息。Invoking this method without a completedBlock is pointless
NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
// 确保传进来的URL类型为NSURL,如果为NSString则进行类型转化
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
// 防止URL为空时程序崩溃
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
// 执行图片下载操作的集合
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
__weak SDWebImageCombinedOperation *weakOperation = operation;
// 图片URL是否失败
BOOL isFailedUrl = NO;
// 创建一个互斥锁,保证此时没有其它线程对self对象进行修改
@synchronized (self.failedURLs) {
isFailedUrl = [self.failedURLs containsObject:url];
}
// URL长度为0,或 获取该URL已下载失败过且操作类型没有禁用掉黑名单列表,则该图片就下载失败,返回失败block
if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
// 在主线程中执行回调
dispatch_main_sync_safe(^{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
});
return operation;
}
// 创建一个互斥锁,保证此时没有其它线程对self对象进行修改
@synchronized (self.runningOperations) {
// 将操作加入到当前运行操作的数组中
[self.runningOperations addObject:operation];
}
NSString *key = [self cacheKeyForURL:url];
// 根据key从缓存里面查找
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
// 操作被取消,则从当前运行操作的数组中删除该操作
if (operation.isCancelled) {
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
return;
}
// 没有图片或操作类型会刷新缓存 且 delegate允许下载图片
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
// // 有图片 并且操作类型为 SDWebImageRefreshCached(先用缓存图片回调block,图片下载完成后再回调block)
if (image && options & SDWebImageRefreshCached) {
dispatch_main_sync_safe(^{
// If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES, url);
});
}
// download if no image or requested to refresh anyway, and download allowed by delegate
// 如果缓存没有图片或请求刷新,并通过委托下载图片,则下载图片
SDWebImageDownloaderOptions downloaderOptions = 0;
if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
if (image && options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
// 下载图片
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
__strong __typeof(weakOperation) strongOperation = weakOperation;
if (!strongOperation || strongOperation.isCancelled) {
// Do nothing if the operation was cancelled
// See #699 for more details
// if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data
// 操作取消则不做任何处理
// 如果这里进行了completedBlock回调,由于对同一个对象是竞争条件,可能会覆盖新数据?????
}
else if (error) {
// 出错
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) {
// 下载失败图片的URL添加到失败URL数组
@synchronized (self.failedURLs) {
[self.failedURLs addObject:url];
}
}
}
// 下载成功
else {
//
if ((options & SDWebImageRetryFailed)) {
// 操作类型为失败重新刷新下载,失败图片的URL添加到失败URL数组
@synchronized (self.failedURLs) {
[self.failedURLs removeObject:url];
}
}
// 是否存储在磁盘
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
if (options & SDWebImageRefreshCached && image && !downloadedImage) {
// Image refresh hit the NSURLCache cache, do not call the completion block
}
// 图片下载成功且需要转换图片
else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
// 在全局队列中异步进行操作
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];
}
// completedBlock回调
dispatch_main_sync_safe(^{
if (strongOperation && !strongOperation.isCancelled) {
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
});
}
// 存储图片并completedBlock回调
else {
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);
}
});
}
}
// 图片下载完成,则在运行的操作数组中删除该操作
if (finished) {
@synchronized (self.runningOperations) {
if (strongOperation) {
[self.runningOperations removeObject:strongOperation];
}
}
}
}];
// 取消操作,从数组中删除该操作
operation.cancelBlock = ^{
[subOperation cancel];
@synchronized (self.runningOperations) {
__strong __typeof(weakOperation) strongOperation = weakOperation;
if (strongOperation) {
[self.runningOperations removeObject:strongOperation];
}
}
};
}
// 有图片且线程没有被取消,则返回有图片的completedBlock
else if (image) {
dispatch_main_sync_safe(^{
__strong __typeof(weakOperation) strongOperation = weakOperation;
if (strongOperation && !strongOperation.isCancelled) {
completedBlock(image, nil, cacheType, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
// 图片没有在缓存且不允许委托方法下载图片
else {
// Image not in cache and download disallowed by delegate
dispatch_main_sync_safe(^{
__strong __typeof(weakOperation) strongOperation = weakOperation;
if (strongOperation && !weakOperation.isCancelled) {
completedBlock(nil, nil, SDImageCacheTypeNone, YES, url);
}
});
@synchronized (self.runningOperations) {
[self.runningOperations removeObject:operation];
}
}
}];
return operation;
}
/**
* 将图片存入缓存
*
* @param image 图片
* @param url 图片URL
*/
- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url {
if (image && url) {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache storeImage:image forKey:key toDisk:YES];
}
}
/**
* 取消掉当前所有的下载图片的operation
*/
- (void)cancelAll {
@synchronized (self.runningOperations) {
NSArray *copiedOperations = [self.runningOperations copy];
[copiedOperations makeObjectsPerformSelector:@selector(cancel)];
[self.runningOperations removeObjectsInArray:copiedOperations];
}
}
/**
* 检查是否有一个或者多个operation正在执行(简单来说就是check是否有图片在下载)
*
* @return <#return value description#>
*/
- (BOOL)isRunning {
BOOL isRunning = NO;
@synchronized(self.runningOperations) {
isRunning = (self.runningOperations.count > 0);
}
return isRunning;
}
@end
@implementation SDWebImageCombinedOperation
- (void)setCancelBlock:(SDWebImageNoParamsBlock)cancelBlock {
// check if the operation is already cancelled, then we just call the cancelBlock
if (self.isCancelled) {
if (cancelBlock) {
cancelBlock();
}
_cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes
} else {
_cancelBlock = [cancelBlock copy];
}
}
- (void)cancel {
self.cancelled = YES;
if (self.cacheOperation) {
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock) {
self.cancelBlock();
// TODO: this is a temporary fix to #809.
// Until we can figure the exact cause of the crash, going with the ivar instead of the setter
// self.cancelBlock = nil;
_cancelBlock = nil;
}
}
@end
@implementation SDWebImageManager (Deprecated)
// 废弃的方法:deprecated method, uses the non deprecated method
// adapter for the completion block
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
return [self downloadImageWithURL:url
options:options
progress:progressBlock
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (completedBlock) {
completedBlock(image, error, cacheType, finished);
}
}];
}
@end
SDWebImagePrefecher注释:
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #1d9421}p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; min-height: 16.0px}p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #c91b13}p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo}p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px 'PingFang SC'; color: #1d9421}p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #c32275}span.s1 {font-variant-ligatures: no-common-ligatures}span.s2 {font-variant-ligatures: no-common-ligatures; color: #822e0e}span.s3 {font-variant-ligatures: no-common-ligatures; color: #c32275}span.s4 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures}span.s5 {font: 14.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures}span.s6 {font-variant-ligatures: no-common-ligatures; color: #0435ff}span.s7 {font-variant-ligatures: no-common-ligatures; color: #000000}span.s8 {font-variant-ligatures: no-common-ligatures; color: #1d9421}span.s9 {font: 14.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures; color: #1d9421}span.s10 {font: 14.0px Menlo; font-variant-ligatures: no-common-ligatures; color: #000000}
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImagePrefetcher.h"
@interface SDWebImagePrefetcher ()
@property (strong, nonatomic) SDWebImageManager *manager;
// 预取图片地址数组
@property (strong, nonatomic) NSArray *prefetchURLs;
// 请求数
@property (assign, nonatomic) NSUInteger requestedCount;
@property (assign, nonatomic) NSUInteger skippedCount;
// 完成数
@property (assign, nonatomic) NSUInteger finishedCount;
@property (assign, nonatomic) NSTimeInterval startedTime;
@property (copy, nonatomic) SDWebImagePrefetcherCompletionBlock completionBlock;
@property (copy, nonatomic) SDWebImagePrefetcherProgressBlock progressBlock;
@end
@implementation SDWebImagePrefetcher
+ (SDWebImagePrefetcher *)sharedImagePrefetcher {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
- (id)init {
return [self initWithImageManager:[SDWebImageManager new]];
}
- (id)initWithImageManager:(SDWebImageManager *)manager {
if ((self = [super init])) {
_manager = manager;
_options = SDWebImageLowPriority;
_prefetcherQueue = dispatch_get_main_queue();
self.maxConcurrentDownloads = 3;
}
return self;
}
- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads {
self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads;
}
- (NSUInteger)maxConcurrentDownloads {
return self.manager.imageDownloader.maxConcurrentDownloads;
}
/**
* 开始预取第几张图片
*
* @param index 图片位置
*/
- (void)startPrefetchingAtIndex:(NSUInteger)index {
if (index >= self.prefetchURLs.count) return;
// 请求数+1
self.requestedCount++;
[self.manager downloadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!finished) return;
// 完成数+1
self.finishedCount++;
if (image) {
if (self.progressBlock) {
self.progressBlock(self.finishedCount,[self.prefetchURLs count]);
}
}
else {
if (self.progressBlock) {
self.progressBlock(self.finishedCount,[self.prefetchURLs count]);
}
// 图片没有下载完,跳过数+1:Add last failed
self.skippedCount++;
}
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) {
[self.delegate imagePrefetcher:self
didPrefetchURL:self.prefetchURLs[index]
finishedCount:self.finishedCount
totalCount:self.prefetchURLs.count
];
}
if (self.prefetchURLs.count > self.requestedCount) {
// 预取图片数 > 请求数,继续预取图片
dispatch_async(self.prefetcherQueue, ^{
[self startPrefetchingAtIndex:self.requestedCount];
});
} else if (self.finishedCount == self.requestedCount) {
// 完成数 = 请求数,该图片下载完成,进行回调
[self reportStatus]; // 报告图片完成状态
if (self.completionBlock) {
self.completionBlock(self.finishedCount, self.skippedCount);
self.completionBlock = nil;
}
self.progressBlock = nil;
}
}];
}
/**
* 报告预取图片完成状态
*/
- (void)reportStatus {
NSUInteger total = [self.prefetchURLs count];
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) {
[self.delegate imagePrefetcher:self
didFinishWithTotalCount:(total - self.skippedCount)
skippedCount:self.skippedCount
];
}
}
/**
* 根据图片地址数组预取图片
*
* @param urls 图片地址数组
*/
- (void)prefetchURLs:(NSArray *)urls {
[self prefetchURLs:urls progress:nil completed:nil];
}
- (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock {
[self cancelPrefetching]; // 先取消图片预取,防止重复操作:Prevent duplicate prefetch request
self.startedTime = CFAbsoluteTimeGetCurrent();
self.prefetchURLs = urls;
self.completionBlock = completionBlock;
self.progressBlock = progressBlock;
if (urls.count == 0) {
if (completionBlock) {
completionBlock(0,0);
}
} else {
// 循环预取图片:Starts prefetching from the very first image on the list with the max allowed concurrency
NSUInteger listCount = self.prefetchURLs.count;
for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) {
[self startPrefetchingAtIndex:i];
}
}
}
/**
* 取消图片预取
*/
- (void)cancelPrefetching {
self.prefetchURLs = nil;
self.skippedCount = 0;
self.requestedCount = 0;
self.finishedCount = 0;
[self.manager cancelAll];
}
@end