fix quary original cache for transformed image instead of downloadingq

This commit is contained in:
zxiou 2020-04-26 17:41:45 +08:00
parent 9e3bcf19e3
commit a84ade991c
5 changed files with 124 additions and 4 deletions

View File

@ -42,6 +42,24 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType);
typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCacheType);
#pragma mark - Context Options
/**
A `UIImage` instance from `SDWebImageCache` when miss normal cache and you specify `SDWebImageContextOriginalQueryCacheType`
and image cache hit. This can be used directly instead of downloading.
@note If you don't implement `SDWebImageContextOriginalQueryCacheType` support, you do not need to care abot this context option.
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextOriginalCachedImage;
/**
A `NSData` instance from `SDWebImageCache` when miss normal cache and you specify `SDWebImageContextOriginalQueryCacheType`
and image cache hit. This can be used directly instead of downloading.
@note If you don't implement `SDWebImageContextOriginalQueryCacheType` support, you do not need to care abot this context option.
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextOriginalCachedImageData;
#pragma mark - Helper method
/**
This is the built-in decoding process for image query from cache.
@note If you want to implement your custom loader with `queryImageForKey:options:context:completion:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image.
@ -54,6 +72,8 @@ typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCach
*/
FOUNDATION_EXPORT UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context);
#pragma mark - SDImageCache
/**
This is the image cache protocol to provide custom image cache for `SDWebImageManager`.
Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`).

View File

@ -83,3 +83,8 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS
return image;
}
#pragma mark - Context option
SDWebImageContextOption const SDWebImageContextOriginalCachedImage = @"originalCachedImage";
SDWebImageContextOption const SDWebImageContextOriginalCachedImageData = @"originalCachedImageData";

View File

@ -272,6 +272,13 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextQueryC
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextStoreCacheType;
/**
The same behavior like `SDWebImageContextQueryCacheType`, but control the query cache type for the original image when you use image transformer feature. This allows the detail control of cache query for these two images. For example, if you want to query the transformed image from both memory/disk cache, query the original image from disk cache only, use `[.queryCacheType : .all, .originalQueryCacheType : .disk]`
If not provide or the value is invalid, we will use `SDImageCacheTypeNone`, which does not query the original image from cache. (NSNumber)
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextOriginalQueryCacheType;
/**
The same behavior like `SDWebImageContextStoreCacheType`, but control the store cache type for the original image when you use image transformer feature. This allows the detail control of cache storage for these two images. For example, if you want to store the transformed image into both memory/disk cache, store the original image into disk cache only, use `[.storeCacheType : .all, .originalStoreCacheType : .disk]`
If not provide or the value is invalid, we will use `SDImageCacheTypeNone`, which does not store the original image into cache. (NSNumber)

View File

@ -129,6 +129,7 @@ SDWebImageContextOption const SDWebImageContextImagePreserveAspectRatio = @"imag
SDWebImageContextOption const SDWebImageContextImageThumbnailPixelSize = @"imageThumbnailPixelSize";
SDWebImageContextOption const SDWebImageContextQueryCacheType = @"queryCacheType";
SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType";
SDWebImageContextOption const SDWebImageContextOriginalQueryCacheType = @"originalQueryCacheType";
SDWebImageContextOption const SDWebImageContextOriginalStoreCacheType = @"originalStoreCacheType";
SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass";
SDWebImageContextOption const SDWebImageContextDownloadRequestModifier = @"downloadRequestModifier";

View File

@ -228,7 +228,7 @@ static id<SDImageLoader> _defaultImageLoader;
#pragma mark - Private
// Query cache process
// Query normal cache process
- (void)callCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation
url:(nonnull NSURL *)url
options:(SDWebImageOptions)options
@ -242,13 +242,15 @@ static id<SDImageLoader> _defaultImageLoader;
} else {
imageCache = self.imageCache;
}
// Check whether we should query cache
BOOL shouldQueryCache = !SD_OPTIONS_CONTAINS(options, SDWebImageFromLoaderOnly);
// Get the query cache type
SDImageCacheType queryCacheType = SDImageCacheTypeAll;
if (context[SDWebImageContextQueryCacheType]) {
queryCacheType = [context[SDWebImageContextQueryCacheType] integerValue];
}
// Check whether we should query cache
BOOL shouldQueryCache = !SD_OPTIONS_CONTAINS(options, SDWebImageFromLoaderOnly);
if (shouldQueryCache) {
NSString *key = [self cacheKeyForURL:url context:context];
@weakify(operation);
@ -260,6 +262,12 @@ static id<SDImageLoader> _defaultImageLoader;
[self safelyRemoveOperationFromRunning:operation];
return;
}
else if (!cachedImage) {
// Miss normal cache, we have a chance to quary original image from cache instead of downloading
[self callOriginalCacheProcessForOperation:operation url:url options:options context:context progress:progressBlock completed:completedBlock];
return ;
}
// Continue download process
[self callDownloadProcessForOperation:operation url:url options:options context:context cachedImage:cachedImage cachedData:cachedData cacheType:cacheType progress:progressBlock completed:completedBlock];
}];
@ -269,6 +277,77 @@ static id<SDImageLoader> _defaultImageLoader;
}
}
// Query original cache process
- (void)callOriginalCacheProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation
url:(nonnull NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock {
// Grab the image cache to use
id<SDImageCache> imageCache;
if ([context[SDWebImageContextImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextImageCache];
} else {
imageCache = self.imageCache;
}
// Get the original query cache type
SDImageCacheType originalQueryCacheType = SDImageCacheTypeNone;
if (context[SDWebImageContextOriginalQueryCacheType]) {
originalQueryCacheType = [context[SDWebImageContextOriginalQueryCacheType] integerValue];
}
// Check whether we should query original cache
BOOL shouldQueryOriginalCache = context[SDWebImageContextImageTransformer] && (originalQueryCacheType != SDImageCacheTypeNone);
if (shouldQueryOriginalCache) {
// Change originContext to mutable
SDWebImageMutableContext * __block originContext;
if (context) {
originContext = [context mutableCopy];
} else {
originContext = [NSMutableDictionary dictionary];
}
// disable transformer for cache key generation
id<SDImageTransformer> transformer = originContext[SDWebImageContextImageTransformer];
originContext[SDWebImageContextImageTransformer] = [NSNull null];
NSString *key = [self cacheKeyForURL:url context:originContext];
@weakify(operation);
operation.cacheOperation = [imageCache queryImageForKey:key options:options context:context cacheType:originalQueryCacheType completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) {
@strongify(operation);
if (!operation || operation.isCancelled) {
// Image combined operation cancelled by user
[self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCancelled userInfo:@{NSLocalizedDescriptionKey : @"Operation cancelled by user during querying the cache"}] url:url];
[self safelyRemoveOperationFromRunning:operation];
return;
}
// Add original transformer
if (transformer) {
originContext[SDWebImageContextImageTransformer] = transformer;
}
// Pass the original cached image and date to the next process
if (cachedImage) {
originContext[SDWebImageContextOriginalCachedImage] = cachedImage;
}
if (cachedData) {
originContext[SDWebImageContextOriginalCachedImageData] = cachedData;
}
// Continue download process
[self callDownloadProcessForOperation:operation url:url options:options context:[originContext copy] cachedImage:nil cachedData:nil cacheType:originalQueryCacheType progress:progressBlock completed:completedBlock];
}];
}
else {
// Continue download process
[self callDownloadProcessForOperation:operation url:url options:options context:context cachedImage:nil cachedData:nil cacheType:originalQueryCacheType progress:progressBlock completed:completedBlock];
}
}
// Download process
- (void)callDownloadProcessForOperation:(nonnull SDWebImageCombinedOperation *)operation
url:(nonnull NSURL *)url
@ -286,9 +365,13 @@ static id<SDImageLoader> _defaultImageLoader;
} else {
imageLoader = self.imageLoader;
}
// Get original chched image
UIImage *originalCachedImage = context[SDWebImageContextOriginalCachedImage];
// Check whether we should download image from network
BOOL shouldDownload = !SD_OPTIONS_CONTAINS(options, SDWebImageFromCacheOnly);
shouldDownload &= (!cachedImage || options & SDWebImageRefreshCached);
shouldDownload &= ((!cachedImage && !originalCachedImage) || options & SDWebImageRefreshCached);
shouldDownload &= (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]);
shouldDownload &= [imageLoader canRequestImageForURL:url];
if (shouldDownload) {
@ -344,6 +427,10 @@ static id<SDImageLoader> _defaultImageLoader;
} else if (cachedImage) {
[self callCompletionBlockForOperation:operation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];
[self safelyRemoveOperationFromRunning:operation];
} else if (originalCachedImage) {
// Still use the store cache process, but only instead of downloading
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:originalCachedImage downloadedData:context[SDWebImageContextOriginalCachedImageData] finished:YES progress:progressBlock completed:completedBlock];
[self safelyRemoveOperationFromRunning:operation];
} else {
// Image not in cache and download disallowed by delegate
[self callCompletionBlockForOperation:operation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url];