Fix the logic for choosing the cache instance when using transformer. The original cache should be used when query/store the original image; The transformed cache should be used when query/store transformed image.

Added test case `test16ThatTransformerUseDifferentCacheForOriginalAndTransformedImage`
This commit is contained in:
DreamPiggy 2021-03-09 15:39:36 +08:00
parent ae2ca99465
commit 140db1ca46
2 changed files with 71 additions and 44 deletions

View File

@ -260,25 +260,12 @@ static id<SDImageLoader> _defaultImageLoader;
} else {
imageCache = self.imageCache;
}
// Get the query cache type
SDImageCacheType queryCacheType = SDImageCacheTypeAll;
if (context[SDWebImageContextQueryCacheType]) {
queryCacheType = [context[SDWebImageContextQueryCacheType] integerValue];
}
// Get the transformer
id<SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
if (![transformer conformsToProtocol:@protocol(SDImageTransformer)]) {
transformer = nil;
}
if (transformer) {
// Use standandalone cache for original image query
if ([context[SDWebImageContextOriginalImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextOriginalImageCache];
}
}
// Check whether we should query cache
BOOL shouldQueryCache = !SD_OPTIONS_CONTAINS(options, SDWebImageFromLoaderOnly);
if (shouldQueryCache) {
@ -313,14 +300,18 @@ static id<SDImageLoader> _defaultImageLoader;
context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock {
// Grab the image cache to use
// Grab the image cache to use, choose standalone original cache firstly
id<SDImageCache> imageCache;
if ([context[SDWebImageContextImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextImageCache];
if ([context[SDWebImageContextOriginalImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextOriginalImageCache];
} else {
imageCache = self.imageCache;
// if no standalone cache available, use default cache
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]) {
@ -352,12 +343,7 @@ static id<SDImageLoader> _defaultImageLoader;
[self safelyRemoveOperationFromRunning:operation];
return;
}
// Add original transformer
if (transformer) {
originContext[SDWebImageContextImageTransformer] = transformer;
}
// Use the store cache process instead of downloading, and ignore .refreshCached option for now
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:cachedImage downloadedData:cachedData finished:YES progress:progressBlock completed:completedBlock];
@ -466,6 +452,18 @@ static id<SDImageLoader> _defaultImageLoader;
finished:(BOOL)finished
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock {
// Grab the image cache to use, choose standalone original cache firstly
id<SDImageCache> imageCache;
if ([context[SDWebImageContextOriginalImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextOriginalImageCache];
} else {
// if no standalone cache available, use default cache
if ([context[SDWebImageContextImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextImageCache];
} else {
imageCache = self.imageCache;
}
}
// the target image store cache type
SDImageCacheType storeCacheType = SDImageCacheTypeAll;
if (context[SDWebImageContextStoreCacheType]) {
@ -500,14 +498,14 @@ static id<SDImageLoader> _defaultImageLoader;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
@autoreleasepool {
NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url];
[self storeImage:downloadedImage imageData:cacheData forKey:key cacheType:targetStoreCacheType options:options context:context completion:^{
[self storeImage:downloadedImage imageData:cacheData forKey:key imageCache:imageCache cacheType:targetStoreCacheType options:options context:context completion:^{
// Continue transform process
[self callTransformProcessForOperation:operation url:url options:options context:context originalImage:downloadedImage originalData:downloadedData finished:finished progress:progressBlock completed:completedBlock];
}];
}
});
} else {
[self storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:targetStoreCacheType options:options context:context completion:^{
[self storeImage:downloadedImage imageData:downloadedData forKey:key imageCache:imageCache cacheType:targetStoreCacheType options:options context:context completion:^{
// Continue transform process
[self callTransformProcessForOperation:operation url:url options:options context:context originalImage:downloadedImage originalData:downloadedData finished:finished progress:progressBlock completed:completedBlock];
}];
@ -528,6 +526,13 @@ static id<SDImageLoader> _defaultImageLoader;
finished:(BOOL)finished
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;
}
// the target image store cache type
SDImageCacheType storeCacheType = SDImageCacheTypeAll;
if (context[SDWebImageContextStoreCacheType]) {
@ -558,7 +563,7 @@ static id<SDImageLoader> _defaultImageLoader;
} else {
cacheData = (imageWasTransformed ? nil : originalData);
}
[self storeImage:transformedImage imageData:cacheData forKey:key cacheType:storeCacheType options:options context:context completion:^{
[self storeImage:transformedImage imageData:cacheData forKey:key imageCache:imageCache cacheType:storeCacheType options:options context:context completion:^{
[self callCompletionBlockForOperation:operation completion:completedBlock image:transformedImage data:originalData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
}];
} else {
@ -585,27 +590,11 @@ static id<SDImageLoader> _defaultImageLoader;
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)data
forKey:(nullable NSString *)key
imageCache:(nonnull id<SDImageCache>)imageCache
cacheType:(SDImageCacheType)cacheType
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
completion:(nullable SDWebImageNoParamsBlock)completion {
id<SDImageCache> imageCache;
if ([context[SDWebImageContextImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextImageCache];
} else {
imageCache = self.imageCache;
}
// Get the transformer
id<SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
if (![transformer conformsToProtocol:@protocol(SDImageTransformer)]) {
transformer = nil;
}
if (transformer) {
// Use standandalone cache for original image query
if ([context[SDWebImageContextOriginalImageCache] conformsToProtocol:@protocol(SDImageCache)]) {
imageCache = context[SDWebImageContextOriginalImageCache];
}
}
BOOL waitStoreCache = SD_OPTIONS_CONTAINS(options, SDWebImageWaitStoreCache);
// Check whether we should wait the store cache finished. If not, callback immediately
[imageCache storeImage:image imageData:data forKey:key cacheType:cacheType completion:^{

View File

@ -379,6 +379,44 @@
[self waitForExpectationsWithCommonTimeout];
}
- (void)test16ThatTransformerUseDifferentCacheForOriginalAndTransformedImage {
XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer use different cache instance for original image and transformed image works"];
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/103x103.png"];
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
NSString *originalKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
NSString *transformedKey = [SDWebImageManager.sharedManager cacheKeyForURL:url context:@{SDWebImageContextImageTransformer : transformer}];
SDImageCache *transformerCache = [[SDImageCache alloc] initWithNamespace:@"TransformerCache"];
SDImageCache *originalCache = [[SDImageCache alloc] initWithNamespace:@"OriginalCache"];
[[SDWebImageManager sharedManager] loadImageWithURL:url options:SDWebImageWaitStoreCache context:
@{SDWebImageContextImageTransformer : transformer,
SDWebImageContextOriginalImageCache : originalCache,
SDWebImageContextImageCache : transformerCache,
SDWebImageContextOriginalStoreCacheType: @(SDImageCacheTypeMemory),
SDWebImageContextStoreCacheType: @(SDImageCacheTypeMemory)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
// Get the transformed image
expect(image).equal(transformer.testImage);
// Now, the original image is stored into originalCache
UIImage *originalImage = [originalCache imageFromMemoryCacheForKey:originalKey];
expect(originalImage.size).equal(CGSizeMake(103, 103));
expect([transformerCache imageFromMemoryCacheForKey:originalKey]).beNil();
// The transformed image is stored into transformerCache
UIImage *transformedImage = [transformerCache imageFromMemoryCacheForKey:transformedKey];
expect(image).equal(transformedImage);
expect([originalCache imageFromMemoryCacheForKey:transformedKey]).beNil();
[originalCache clearWithCacheType:SDImageCacheTypeAll completion:nil];
[transformerCache clearWithCacheType:SDImageCacheTypeAll completion:nil];
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kAsyncTestTimeout * 10 handler:nil];
}
- (NSString *)testJPEGPath {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
return [testBundle pathForResource:@"TestImage" ofType:@"jpg"];