From fbe76bc43666aaa27b510aeef0ecf2e87e27c3b1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 1 Apr 2020 17:01:51 +0800 Subject: [PATCH 1/7] Added new query cache type support, including the SDImageCache API and context option --- SDWebImage/Core/SDImageCache.h | 13 +++++++++++++ SDWebImage/Core/SDImageCache.m | 22 ++++++++++++++++++---- SDWebImage/Core/SDImageCacheDefine.h | 2 ++ SDWebImage/Core/SDImageCachesManager.m | 22 +++++++++++----------- SDWebImage/Core/SDWebImageDefine.h | 6 ++++++ SDWebImage/Core/SDWebImageDefine.m | 1 + SDWebImage/Core/SDWebImageManager.m | 7 ++++++- 7 files changed, 57 insertions(+), 16 deletions(-) diff --git a/SDWebImage/Core/SDImageCache.h b/SDWebImage/Core/SDImageCache.h index 1b1afd47..d3d97c17 100644 --- a/SDWebImage/Core/SDImageCache.h +++ b/SDWebImage/Core/SDImageCache.h @@ -268,6 +268,19 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { */ - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock; +/** + * Asynchronously queries the cache with operation and call the completion when done. + * + * @param key The unique key used to store the wanted image. If you want transformed or thumbnail image, calculate the key with `SDTransformedKeyForKey`, `SDThumbnailedKeyForKey`, or generate the cache key from url with `cacheKeyForURL:context:`. + * @param options A mask to specify options to use for this cache query + * @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + * @param queryCacheType Specify where to query the cache from. By default we use `.all`, which means both memory cache and disk cache. You can choose to query memory only or disk only as well. Pass `.none` is invalid and callback with nil immediatelly. + * @param doneBlock The completion block. Will not get called if the operation is cancelled + * + * @return a NSOperation instance containing the cache op + */ +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context cacheType:(SDImageCacheType)queryCacheType done:(nullable SDImageCacheQueryCompletionBlock)doneBlock; + /** * Synchronously query the memory cache. * diff --git a/SDWebImage/Core/SDImageCache.m b/SDWebImage/Core/SDImageCache.m index f7585895..28db40f7 100644 --- a/SDWebImage/Core/SDImageCache.m +++ b/SDWebImage/Core/SDImageCache.m @@ -426,12 +426,23 @@ } - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock { + return [self queryCacheOperationForKey:key options:options context:context cacheType:SDImageCacheTypeAll done:doneBlock]; +} + +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context cacheType:(SDImageCacheType)queryCacheType done:(nullable SDImageCacheQueryCompletionBlock)doneBlock { if (!key) { if (doneBlock) { doneBlock(nil, nil, SDImageCacheTypeNone); } return nil; } + // Invalid cache type + if (queryCacheType == SDImageCacheTypeNone) { + if (doneBlock) { + doneBlock(nil, nil, SDImageCacheTypeNone); + } + return nil; + } id transformer = context[SDWebImageContextImageTransformer]; if (transformer) { @@ -441,7 +452,10 @@ } // First check the in-memory cache... - UIImage *image = [self imageFromMemoryCacheForKey:key]; + UIImage *image; + if (queryCacheType != SDImageCacheTypeDisk) { + image = [self imageFromMemoryCacheForKey:key]; + } if (image) { if (options & SDImageCacheDecodeFirstFrameOnly) { @@ -464,7 +478,7 @@ } } - BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryMemoryData)); + BOOL shouldQueryMemoryOnly = (queryCacheType == SDImageCacheTypeMemory) || (image && !(options & SDImageCacheQueryMemoryData)); if (shouldQueryMemoryOnly) { if (doneBlock) { doneBlock(image, nil, SDImageCacheTypeMemory); @@ -698,7 +712,7 @@ #pragma mark - SDImageCache -- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { +- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { SDImageCacheOptions cacheOptions = 0; if (options & SDWebImageQueryMemoryData) cacheOptions |= SDImageCacheQueryMemoryData; if (options & SDWebImageQueryMemoryDataSync) cacheOptions |= SDImageCacheQueryMemoryDataSync; @@ -709,7 +723,7 @@ if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames; if (options & SDWebImageMatchAnimatedImageClass) cacheOptions |= SDImageCacheMatchAnimatedImageClass; - return [self queryCacheOperationForKey:key options:cacheOptions context:context done:completionBlock]; + return [self queryCacheOperationForKey:key options:cacheOptions context:context cacheType:cacheType done:completionBlock]; } - (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(nullable NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock { diff --git a/SDWebImage/Core/SDImageCacheDefine.h b/SDWebImage/Core/SDImageCacheDefine.h index be4e0211..3ca07ec9 100644 --- a/SDWebImage/Core/SDImageCacheDefine.h +++ b/SDWebImage/Core/SDImageCacheDefine.h @@ -68,12 +68,14 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonn @param key The image cache key @param options A mask to specify options to use for this query @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + @param cacheType Specify where to query the cache from. By default we use `.all`, which means both memory cache and disk cache. You can choose to query memory only or disk only as well. Pass `.none` is invalid and callback with nil immediatelly. @param completionBlock The completion block. Will not get called if the operation is cancelled @return The operation for this query */ - (nullable id)queryImageForKey:(nullable NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context + cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock; /** diff --git a/SDWebImage/Core/SDImageCachesManager.m b/SDWebImage/Core/SDImageCachesManager.m index 6b6f7d8a..de03ed96 100644 --- a/SDWebImage/Core/SDImageCachesManager.m +++ b/SDWebImage/Core/SDImageCachesManager.m @@ -84,7 +84,7 @@ #pragma mark - SDImageCache -- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock { +- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheQueryCompletionBlock)completionBlock { if (!key) { return nil; } @@ -93,30 +93,30 @@ if (count == 0) { return nil; } else if (count == 1) { - return [caches.firstObject queryImageForKey:key options:options context:context completion:completionBlock]; + return [caches.firstObject queryImageForKey:key options:options context:context cacheType:cacheType completion:completionBlock]; } switch (self.queryOperationPolicy) { case SDImageCachesManagerOperationPolicyHighestOnly: { id cache = caches.lastObject; - return [cache queryImageForKey:key options:options context:context completion:completionBlock]; + return [cache queryImageForKey:key options:options context:context cacheType:cacheType completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyLowestOnly: { id cache = caches.firstObject; - return [cache queryImageForKey:key options:options context:context completion:completionBlock]; + return [cache queryImageForKey:key options:options context:context cacheType:cacheType completion:completionBlock]; } break; case SDImageCachesManagerOperationPolicyConcurrent: { SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; - [self concurrentQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + [self concurrentQueryImageForKey:key options:options context:context cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; return operation; } break; case SDImageCachesManagerOperationPolicySerial: { SDImageCachesManagerOperation *operation = [SDImageCachesManagerOperation new]; [operation beginWithTotalCount:caches.count]; - [self serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; + [self serialQueryImageForKey:key options:options context:context cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation]; return operation; } break; @@ -279,11 +279,11 @@ #pragma mark - Concurrent Operation -- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context cacheType:(SDImageCacheType)queryCacheType completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); for (id cache in enumerator) { - [cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + [cache queryImageForKey:key options:options context:context cacheType:queryCacheType completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { if (operation.isCancelled) { // Cancelled return; @@ -422,7 +422,7 @@ #pragma mark - Serial Operation -- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { +- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context cacheType:(SDImageCacheType)queryCacheType completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator> *)enumerator operation:(SDImageCachesManagerOperation *)operation { NSParameterAssert(enumerator); NSParameterAssert(operation); id cache = enumerator.nextObject; @@ -435,7 +435,7 @@ return; } @weakify(self); - [cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + [cache queryImageForKey:key options:options context:context cacheType:queryCacheType completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { @strongify(self); if (operation.isCancelled) { // Cancelled @@ -455,7 +455,7 @@ return; } // Next - [self serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:enumerator operation:operation]; + [self serialQueryImageForKey:key options:options context:context cacheType:queryCacheType completion:completionBlock enumerator:enumerator operation:operation]; }]; } diff --git a/SDWebImage/Core/SDWebImageDefine.h b/SDWebImage/Core/SDWebImageDefine.h index 1be59810..1e8afef8 100644 --- a/SDWebImage/Core/SDWebImageDefine.h +++ b/SDWebImage/Core/SDWebImageDefine.h @@ -259,6 +259,12 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageP */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageThumbnailPixelSize; +/** + A SDImageCacheType raw value which specify the source of cache to query. For example, you can query memory only, query disk only, or query from both memory and disk cache. + If not provide or the value is invalid, we will use `SDImageCacheTypeAll`. (NSNumber) + */ +FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextQueryCacheType; + /** A SDImageCacheType raw value which specify the store cache type when the image has just been downloaded and will be stored to the cache. Specify `SDImageCacheTypeNone` to disable cache storage; `SDImageCacheTypeDisk` to store in disk cache only; `SDImageCacheTypeMemory` to store in memory only. And `SDImageCacheTypeAll` to store in both memory cache and disk cache. If you use image transformer feature, this actually apply for the transformed image, but not the original image itself. Use `SDWebImageContextOriginalStoreCacheType` if you want to control the original image's store cache type at the same time. diff --git a/SDWebImage/Core/SDWebImageDefine.m b/SDWebImage/Core/SDWebImageDefine.m index 866b164d..2809af69 100644 --- a/SDWebImage/Core/SDWebImageDefine.m +++ b/SDWebImage/Core/SDWebImageDefine.m @@ -127,6 +127,7 @@ SDWebImageContextOption const SDWebImageContextImageTransformer = @"imageTransfo SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor"; SDWebImageContextOption const SDWebImageContextImagePreserveAspectRatio = @"imagePreserveAspectRatio"; SDWebImageContextOption const SDWebImageContextImageThumbnailPixelSize = @"imageThumbnailPixelSize"; +SDWebImageContextOption const SDWebImageContextQueryCacheType = @"queryCacheType"; SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType"; SDWebImageContextOption const SDWebImageContextOriginalStoreCacheType = @"originalStoreCacheType"; SDWebImageContextOption const SDWebImageContextAnimatedImageClass = @"animatedImageClass"; diff --git a/SDWebImage/Core/SDWebImageManager.m b/SDWebImage/Core/SDWebImageManager.m index 4d33e6d7..a58831aa 100644 --- a/SDWebImage/Core/SDWebImageManager.m +++ b/SDWebImage/Core/SDWebImageManager.m @@ -220,10 +220,15 @@ static id _defaultImageLoader; } // 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]; + } if (shouldQueryCache) { NSString *key = [self cacheKeyForURL:url context:context]; @weakify(operation); - operation.cacheOperation = [imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { + operation.cacheOperation = [imageCache queryImageForKey:key options:options context:context cacheType:queryCacheType completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) { @strongify(operation); if (!operation || operation.isCancelled) { // Image combined operation cancelled by user From 7f540a6296ec6d8fbf6abf7457816411c5d39519 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 1 Apr 2020 17:03:56 +0800 Subject: [PATCH 2/7] Fix the test cases for cacheType arg --- Tests/Tests/SDImageCacheTests.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 93adcd47..f6961ef4 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -610,7 +610,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; - (void)test50SDImageCacheQueryOp { XCTestExpectation *expectation = [self expectationWithDescription:@"SDImageCache query op works"]; [[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG toDisk:NO completion:nil]; - [[SDImageCachesManager sharedManager] queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + [[SDImageCachesManager sharedManager] queryImageForKey:kTestImageKeyJPEG options:0 context:nil cacheType:SDImageCacheTypeAll completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { expect(image).notTo.beNil(); [expectation fulfill]; }]; @@ -680,7 +680,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicyLowestOnly; - [cachesManager queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + [cachesManager queryImageForKey:kTestImageKeyJPEG options:0 context:nil cacheType:SDImageCacheTypeAll completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { expect(image).to.beNil(); }]; [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:nil]; @@ -699,7 +699,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicyHighestOnly; - [cachesManager queryImageForKey:kTestImageKeyPNG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + [cachesManager queryImageForKey:kTestImageKeyPNG options:0 context:nil cacheType:SDImageCacheTypeAll completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { expect(image).to.beNil(); }]; [cachesManager storeImage:[self testPNGImage] imageData:nil forKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:nil]; @@ -732,7 +732,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent; - [cachesManager queryImageForKey:kConcurrentTestImageKey options:0 context:nil completion:nil]; + [cachesManager queryImageForKey:kConcurrentTestImageKey options:0 context:nil cacheType:SDImageCacheTypeAll completion:nil]; [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; [cachesManager removeImageForKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; @@ -772,7 +772,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; cachesManager.removeOperationPolicy = SDImageCachesManagerOperationPolicySerial; cachesManager.containsOperationPolicy = SDImageCachesManagerOperationPolicySerial; cachesManager.clearOperationPolicy = SDImageCachesManagerOperationPolicySerial; - [cachesManager queryImageForKey:kSerialTestImageKey options:0 context:nil completion:nil]; + [cachesManager queryImageForKey:kSerialTestImageKey options:0 context:nil cacheType:SDImageCacheTypeAll completion:nil]; [cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; [cachesManager removeImageForKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil]; [cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil]; From de153b0a32a98c81b03ca086a10968346f7f1b98 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 1 Apr 2020 17:12:11 +0800 Subject: [PATCH 3/7] Added the new Async API for disk data query, to avoid user to dispatch their own global queu (not IO queue), solve the IO safe issue --- SDWebImage/Core/SDImageCache.h | 9 +++++++++ SDWebImage/Core/SDImageCache.m | 11 +++++++++++ SDWebImage/Core/SDImageCacheDefine.h | 1 + 3 files changed, 21 insertions(+) diff --git a/SDWebImage/Core/SDImageCache.h b/SDWebImage/Core/SDImageCache.h index d3d97c17..ec90efb0 100644 --- a/SDWebImage/Core/SDImageCache.h +++ b/SDWebImage/Core/SDImageCache.h @@ -235,6 +235,15 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { */ - (nullable NSData *)diskImageDataForKey:(nullable NSString *)key; +/** + * Asynchronously load the image data in disk cache. You can decode the image data to image after loaded. + * + * @param key The unique key used to store the wanted image + * @param completionBlock the block to be executed when the check is done. + * @note the completion block will be always executed on the main queue + */ +- (void)diskImageDataQueryForKey:(nullable NSString *)key completion:(nullable SDImageCacheQueryDataCompletionBlock)completionBlock; + /** * Operation that queries the cache asynchronously and call the completion when done. * diff --git a/SDWebImage/Core/SDImageCache.m b/SDWebImage/Core/SDImageCache.m index 28db40f7..6d9a8cd3 100644 --- a/SDWebImage/Core/SDImageCache.m +++ b/SDWebImage/Core/SDImageCache.m @@ -314,6 +314,17 @@ return [self.diskCache containsDataForKey:key]; } +- (void)diskImageDataQueryForKey:(NSString *)key completion:(SDImageCacheQueryDataCompletionBlock)completionBlock { + dispatch_async(self.ioQueue, ^{ + NSData *imageData = [self diskImageDataBySearchingAllPathsForKey:key]; + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(imageData); + }); + } + }); +} + - (nullable NSData *)diskImageDataForKey:(nullable NSString *)key { if (!key) { return nil; diff --git a/SDWebImage/Core/SDImageCacheDefine.h b/SDWebImage/Core/SDImageCacheDefine.h index 3ca07ec9..479d0dd9 100644 --- a/SDWebImage/Core/SDImageCacheDefine.h +++ b/SDWebImage/Core/SDImageCacheDefine.h @@ -36,6 +36,7 @@ typedef NS_ENUM(NSInteger, SDImageCacheType) { }; typedef void(^SDImageCacheCheckCompletionBlock)(BOOL isInCache); +typedef void(^SDImageCacheQueryDataCompletionBlock)(NSData * _Nullable data); typedef void(^SDImageCacheCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key); typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); From ae1f6b9b8c0ae1f8bc2c114bad99e7cfc69bd8b3 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Apr 2020 11:41:17 +0800 Subject: [PATCH 4/7] Revert the removal to the old SDImageCache protocol API, should keep API with to use .all cache type, until next major version --- SDWebImage/Core/SDImageCache.m | 4 ++++ SDWebImage/Core/SDImageCacheDefine.h | 15 +++++++++++++++ SDWebImage/Core/SDImageCachesManager.m | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/SDWebImage/Core/SDImageCache.m b/SDWebImage/Core/SDImageCache.m index 6d9a8cd3..af201386 100644 --- a/SDWebImage/Core/SDImageCache.m +++ b/SDWebImage/Core/SDImageCache.m @@ -723,6 +723,10 @@ #pragma mark - SDImageCache +- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { + return [self queryImageForKey:key options:options context:context cacheType:SDImageCacheTypeAll completion:completionBlock]; +} + - (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { SDImageCacheOptions cacheOptions = 0; if (options & SDWebImageQueryMemoryData) cacheOptions |= SDImageCacheQueryMemoryData; diff --git a/SDWebImage/Core/SDImageCacheDefine.h b/SDWebImage/Core/SDImageCacheDefine.h index 479d0dd9..e2449bfd 100644 --- a/SDWebImage/Core/SDImageCacheDefine.h +++ b/SDWebImage/Core/SDImageCacheDefine.h @@ -62,6 +62,21 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonn @protocol SDImageCache @required +/** + Query the cached image from image cache for given key. The operation can be used to cancel the query. + If image is cached in memory, completion is called synchronously, else aynchronously and depends on the options arg (See `SDWebImageQueryDiskSync`) + + @param key The image cache key + @param options A mask to specify options to use for this query + @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold. + @param completionBlock The completion block. Will not get called if the operation is cancelled + @return The operation for this query + */ +- (nullable id)queryImageForKey:(nullable NSString *)key + options:(SDWebImageOptions)options + context:(nullable SDWebImageContext *)context + completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock; + /** Query the cached image from image cache for given key. The operation can be used to cancel the query. If image is cached in memory, completion is called synchronously, else aynchronously and depends on the options arg (See `SDWebImageQueryDiskSync`) diff --git a/SDWebImage/Core/SDImageCachesManager.m b/SDWebImage/Core/SDImageCachesManager.m index de03ed96..b6b13c12 100644 --- a/SDWebImage/Core/SDImageCachesManager.m +++ b/SDWebImage/Core/SDImageCachesManager.m @@ -84,6 +84,10 @@ #pragma mark - SDImageCache +- (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock { + return [self queryImageForKey:key options:options context:context cacheType:SDImageCacheTypeAll completion:completionBlock]; +} + - (id)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheQueryCompletionBlock)completionBlock { if (!key) { return nil; From d4da82e9c3ce632e4f48217db57edcfd7c6996c5 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Apr 2020 12:18:12 +0800 Subject: [PATCH 5/7] Update the test cases about the custom ImageCache protocol --- Tests/Tests/SDImageCacheTests.m | 32 +++++ Tests/Tests/SDWebImageDownloaderTests.m | 6 +- Tests/Tests/SDWebImageTestCache.h | 13 +- Tests/Tests/SDWebImageTestCache.m | 152 +++++++++++++++++++++++- 4 files changed, 197 insertions(+), 6 deletions(-) diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index f6961ef4..0b195f89 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -793,6 +793,38 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; [self waitForExpectationsWithCommonTimeout]; } +- (void)test58CustomImageCache { + NSString *cachePath = [[self userCacheDirectory] stringByAppendingPathComponent:@"custom"]; + SDImageCacheConfig *config = [[SDImageCacheConfig alloc] init]; + SDWebImageTestCache *cache = [[SDWebImageTestCache alloc] initWithCachePath:cachePath config:config]; + expect(cache.memoryCache).notTo.beNil(); + expect(cache.diskCache).notTo.beNil(); + + // Store + UIImage *image1 = self.testJPEGImage; + NSString *key1 = @"testJPEGImage"; + [cache storeImage:image1 imageData:nil forKey:key1 cacheType:SDImageCacheTypeAll completion:nil]; + // Contain + [cache containsImageForKey:key1 cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeMemory); + }]; + // Query + [cache queryImageForKey:key1 options:0 context:nil cacheType:SDImageCacheTypeAll completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { + expect(image).equal(image1); + expect(data).beNil(); + expect(cacheType).equal(SDImageCacheTypeMemory); + }]; + // Remove + [cache removeImageForKey:key1 cacheType:SDImageCacheTypeAll completion:nil]; + [cache containsImageForKey:key1 cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeNone); + }]; + // Clear + [cache clearWithCacheType:SDImageCacheTypeAll completion:nil]; + NSArray *cacheFiles = [cache.diskCache.fileManager contentsOfDirectoryAtPath:cachePath error:nil]; + expect(cacheFiles.count).equal(0); +} + #pragma mark Helper methods - (UIImage *)testJPEGImage { diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index da0ee89b..4cd877c1 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -474,7 +474,6 @@ [self waitForExpectationsWithCommonTimeout]; } -#if SD_UIKIT - (void)test22ThatCustomDecoderWorksForImageDownload { XCTestExpectation *expectation = [self expectationWithDescription:@"Custom decoder for SDWebImageDownloader not works"]; SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init]; @@ -487,8 +486,8 @@ UIImage *testJPEGImage = [[UIImage alloc] initWithContentsOfFile:testJPEGImagePath]; [downloader downloadImageWithURL:testImageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { - NSData *data1 = UIImagePNGRepresentation(testJPEGImage); - NSData *data2 = UIImagePNGRepresentation(image); + NSData *data1 = [testJPEGImage sd_imageDataAsFormat:SDImageFormatPNG]; + NSData *data2 = [image sd_imageDataAsFormat:SDImageFormatPNG]; if (![data1 isEqualToData:data2]) { XCTFail(@"The image data is not equal to cutom decoder, check -[SDWebImageTestDecoder decodedImageWithData:]"); } @@ -499,7 +498,6 @@ [self waitForExpectationsWithCommonTimeout]; [downloader invalidateSessionAndCancel:YES]; } -#endif - (void)test23ThatDownloadRequestModifierWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Download request modifier not works"]; diff --git a/Tests/Tests/SDWebImageTestCache.h b/Tests/Tests/SDWebImageTestCache.h index 0736c698..8029ff4d 100644 --- a/Tests/Tests/SDWebImageTestCache.h +++ b/Tests/Tests/SDWebImageTestCache.h @@ -9,9 +9,9 @@ #import #import +#import // A really naive implementation of custom memory cache and disk cache - @interface SDWebImageTestMemoryCache : NSObject @property (nonatomic, strong, nonnull) SDImageCacheConfig *config; @@ -26,3 +26,14 @@ @property (nonatomic, strong, nonnull) NSFileManager *fileManager; @end + +// A really naive implementation of custom image cache using memory cache and disk cache +@interface SDWebImageTestCache : NSObject + +@property (nonatomic, strong, nonnull) SDImageCacheConfig *config; +@property (nonatomic, strong, nonnull) SDWebImageTestMemoryCache *memoryCache; +@property (nonatomic, strong, nonnull) SDWebImageTestDiskCache *diskCache; + +- (nullable instancetype)initWithCachePath:(nonnull NSString *)cachePath config:(nonnull SDImageCacheConfig *)config; + +@end diff --git a/Tests/Tests/SDWebImageTestCache.m b/Tests/Tests/SDWebImageTestCache.m index 68b2a154..143f2c80 100644 --- a/Tests/Tests/SDWebImageTestCache.m +++ b/Tests/Tests/SDWebImageTestCache.m @@ -8,7 +8,7 @@ */ #import "SDWebImageTestCache.h" -#import +#import #import "SDFileAttributeHelper.h" static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hackemist.SDWebImageTestDiskCache"; @@ -122,3 +122,153 @@ static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hac } @end + +@implementation SDWebImageTestCache + +- (instancetype)initWithCachePath:(NSString *)cachePath config:(SDImageCacheConfig *)config { + self = [super init]; + if (self) { + self.config = config; + self.memoryCache = [[SDWebImageTestMemoryCache alloc] initWithConfig:config]; + self.diskCache = [[SDWebImageTestDiskCache alloc] initWithCachePath:cachePath config:config]; + } + return self; +} + +- (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: + break; + case SDImageCacheTypeMemory: + [self.memoryCache removeAllObjects]; + break; + case SDImageCacheTypeDisk: + [self.diskCache removeAllData]; + break; + case SDImageCacheTypeAll: + [self.memoryCache removeAllObjects]; + [self.diskCache removeAllData]; + break; + default: + break; + } + if (completionBlock) { + completionBlock(); + } +} + +- (void)containsImageForKey:(nullable NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock { + SDImageCacheType containsCacheType = SDImageCacheTypeNone; + switch (cacheType) { + case SDImageCacheTypeNone: + break; + case SDImageCacheTypeMemory: + containsCacheType = [self.memoryCache objectForKey:key] ? SDImageCacheTypeMemory : SDImageCacheTypeNone; + break; + case SDImageCacheTypeDisk: + containsCacheType = [self.diskCache containsDataForKey:key] ? SDImageCacheTypeDisk : SDImageCacheTypeNone; + break; + case SDImageCacheTypeAll: + if ([self.memoryCache objectForKey:key]) { + containsCacheType = SDImageCacheTypeMemory; + } else if ([self.diskCache containsDataForKey:key]) { + containsCacheType = SDImageCacheTypeDisk; + } + default: + break; + } + if (completionBlock) { + completionBlock(containsCacheType); + } +} + +- (nullable id)queryImageForKey:(nullable NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { + return [self queryImageForKey:key options:options context:context cacheType:SDImageCacheTypeAll completion:completionBlock]; +} + +- (nullable id)queryImageForKey:(nullable NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock { + UIImage *image; + NSData *data; + SDImageCacheType resultCacheType = SDImageCacheTypeNone; + switch (cacheType) { + case SDImageCacheTypeNone: + break; + case SDImageCacheTypeMemory: + image = [self.memoryCache objectForKey:key]; + if (image) { + resultCacheType = SDImageCacheTypeMemory; + } + break; + case SDImageCacheTypeDisk: + data = [self.diskCache dataForKey:key]; + image = [UIImage sd_imageWithData:data]; + if (data) { + resultCacheType = SDImageCacheTypeDisk; + } + break; + case SDImageCacheTypeAll: + image = [self.memoryCache objectForKey:key]; + if (image) { + resultCacheType = SDImageCacheTypeMemory; + } else { + data = [self.diskCache dataForKey:key]; + image = [UIImage sd_imageWithData:data]; + if (data) { + resultCacheType = SDImageCacheTypeDisk; + } + } + break; + default: + break; + } + if (completionBlock) { + completionBlock(image, data, resultCacheType); + } + return nil; +} + +- (void)removeImageForKey:(nullable NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: + break; + case SDImageCacheTypeMemory: + [self.memoryCache removeObjectForKey:key]; + break; + case SDImageCacheTypeDisk: + [self.diskCache removeDataForKey:key]; + break; + case SDImageCacheTypeAll: + [self.memoryCache removeObjectForKey:key]; + [self.diskCache removeDataForKey:key]; + break; + default: + break; + } + if (completionBlock) { + completionBlock(); + } +} + +- (void)storeImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock { + switch (cacheType) { + case SDImageCacheTypeNone: + break; + case SDImageCacheTypeMemory: + [self.memoryCache setObject:image forKey:key]; + break; + case SDImageCacheTypeDisk: + [self.diskCache setData:imageData forKey:key]; + break; + case SDImageCacheTypeAll: + [self.memoryCache setObject:image forKey:key]; + [self.diskCache setData:imageData forKey:key]; + break; + default: + break; + } + if (completionBlock) { + completionBlock(); + } +} + +@end From 067174b1fdceb0d14db0a645da581395c3f91855 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Apr 2020 12:49:15 +0800 Subject: [PATCH 6/7] Added the test case about using the custom cache and loader with context option to manager, full pipeline testing --- Tests/Tests/SDImageCacheTests.m | 3 +++ Tests/Tests/SDWebImageManagerTests.m | 26 ++++++++++++++++++++++++++ Tests/Tests/SDWebImageTestCache.h | 2 ++ Tests/Tests/SDWebImageTestCache.m | 23 +++++++++++++++++++++-- Tests/Tests/SDWebImageTestLoader.h | 2 ++ Tests/Tests/SDWebImageTestLoader.m | 9 +++++++++ 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 0b195f89..96fb0f48 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -800,6 +800,8 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; expect(cache.memoryCache).notTo.beNil(); expect(cache.diskCache).notTo.beNil(); + // Clear + [cache clearWithCacheType:SDImageCacheTypeAll completion:nil]; // Store UIImage *image1 = self.testJPEGImage; NSString *key1 = @"testJPEGImage"; @@ -816,6 +818,7 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png"; }]; // Remove [cache removeImageForKey:key1 cacheType:SDImageCacheTypeAll completion:nil]; + // Contain [cache containsImageForKey:key1 cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) { expect(containsCacheType).equal(SDImageCacheTypeNone); }]; diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index c75fc950..ba61529f 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -8,6 +8,8 @@ #import "SDTestCase.h" #import "SDWebImageTestTransformer.h" +#import "SDWebImageTestCache.h" +#import "SDWebImageTestLoader.h" @interface SDWebImageManagerTests : SDTestCase @@ -268,6 +270,30 @@ }]; } +- (void)test14ThatCustomCacheAndLoaderWorks { + XCTestExpectation *expectation = [self expectationWithDescription:@"Custom Cache and Loader during manger query"]; + NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/100x100.png"]; + SDWebImageContext *context = @{ + SDWebImageContextImageCache : SDWebImageTestCache.sharedCache, + SDWebImageContextImageLoader : SDWebImageTestLoader.sharedLoader + }; + [SDWebImageTestCache.sharedCache clearWithCacheType:SDImageCacheTypeAll completion:nil]; + [SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageWaitStoreCache context:context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + expect(image).notTo.beNil(); + expect(image.size.width).equal(100); + expect(image.size.height).equal(100); + expect(data).notTo.beNil(); + NSString *cacheKey = [SDWebImageManager.sharedManager cacheKeyForURL:imageURL]; + // Check Disk Cache (SDWebImageWaitStoreCache behavior) + [SDWebImageTestCache.sharedCache containsImageForKey:cacheKey cacheType:SDImageCacheTypeDisk completion:^(SDImageCacheType containsCacheType) { + expect(containsCacheType).equal(SDImageCacheTypeDisk); + [expectation fulfill]; + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; diff --git a/Tests/Tests/SDWebImageTestCache.h b/Tests/Tests/SDWebImageTestCache.h index 8029ff4d..6c900c6f 100644 --- a/Tests/Tests/SDWebImageTestCache.h +++ b/Tests/Tests/SDWebImageTestCache.h @@ -36,4 +36,6 @@ - (nullable instancetype)initWithCachePath:(nonnull NSString *)cachePath config:(nonnull SDImageCacheConfig *)config; +@property (nonatomic, class, readonly, nonnull) SDWebImageTestCache *sharedCache; + @end diff --git a/Tests/Tests/SDWebImageTestCache.m b/Tests/Tests/SDWebImageTestCache.m index 143f2c80..d9e34e3d 100644 --- a/Tests/Tests/SDWebImageTestCache.m +++ b/Tests/Tests/SDWebImageTestCache.m @@ -49,7 +49,7 @@ static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hac @implementation SDWebImageTestDiskCache - (nullable NSString *)cachePathForKey:(nonnull NSString *)key { - return [self.cachePath stringByAppendingPathComponent:key]; + return [self.cachePath stringByAppendingPathComponent:key.lastPathComponent]; } - (BOOL)containsDataForKey:(nonnull NSString *)key { @@ -72,7 +72,10 @@ static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hac } - (void)removeAllData { - [self.fileManager removeItemAtPath:self.cachePath error:nil]; + for (NSString *path in [self.fileManager subpathsAtPath:self.cachePath]) { + NSString *filePath = [self.cachePath stringByAppendingPathComponent:path]; + [self.fileManager removeItemAtPath:filePath error:nil]; + } } - (void)removeDataForKey:(nonnull NSString *)key { @@ -125,6 +128,17 @@ static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hac @implementation SDWebImageTestCache ++ (SDWebImageTestCache *)sharedCache { + static dispatch_once_t onceToken; + static SDWebImageTestCache *cache; + dispatch_once(&onceToken, ^{ + NSString *cachePath = [[self userCacheDirectory] stringByAppendingPathComponent:@"SDWebImageTestCache"]; + SDImageCacheConfig *config = SDImageCacheConfig.defaultCacheConfig; + cache = [[SDWebImageTestCache alloc] initWithCachePath:cachePath config:config]; + }); + return cache; +} + - (instancetype)initWithCachePath:(NSString *)cachePath config:(SDImageCacheConfig *)config { self = [super init]; if (self) { @@ -271,4 +285,9 @@ static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hac } } ++ (nullable NSString *)userCacheDirectory { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + return paths.firstObject; +} + @end diff --git a/Tests/Tests/SDWebImageTestLoader.h b/Tests/Tests/SDWebImageTestLoader.h index d6a3f5f9..bd343cd8 100644 --- a/Tests/Tests/SDWebImageTestLoader.h +++ b/Tests/Tests/SDWebImageTestLoader.h @@ -13,4 +13,6 @@ // A really naive implementation of custom image loader using `NSURLSession` @interface SDWebImageTestLoader : NSObject +@property (nonatomic, class, readonly, nonnull) SDWebImageTestLoader *sharedLoader; + @end diff --git a/Tests/Tests/SDWebImageTestLoader.m b/Tests/Tests/SDWebImageTestLoader.m index 22978edb..14f6f7e5 100644 --- a/Tests/Tests/SDWebImageTestLoader.m +++ b/Tests/Tests/SDWebImageTestLoader.m @@ -16,6 +16,15 @@ @implementation SDWebImageTestLoader ++ (SDWebImageTestLoader *)sharedLoader { + static dispatch_once_t onceToken; + static SDWebImageTestLoader *loader; + dispatch_once(&onceToken, ^{ + loader = [[SDWebImageTestLoader alloc] init]; + }); + return loader; +} + - (BOOL)canRequestImageForURL:(NSURL *)url { return YES; } From ce4eced4d45d9985a8abc4d50d085138519e5f15 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 2 Apr 2020 16:15:10 +0800 Subject: [PATCH 7/7] Added the query cache type cases as well, update some documentation --- SDWebImage/Core/SDWebImageDefine.h | 2 +- Tests/Tests/SDWebImageManagerTests.m | 23 +++++++++++++++++++++++ Tests/Tests/SDWebImageTestCache.m | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/SDWebImage/Core/SDWebImageDefine.h b/SDWebImage/Core/SDWebImageDefine.h index 1e8afef8..6f02f279 100644 --- a/SDWebImage/Core/SDWebImageDefine.h +++ b/SDWebImage/Core/SDWebImageDefine.h @@ -260,7 +260,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageP FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageThumbnailPixelSize; /** - A SDImageCacheType raw value which specify the source of cache to query. For example, you can query memory only, query disk only, or query from both memory and disk cache. + A SDImageCacheType raw value which specify the source of cache to query. Specify `SDImageCacheTypeDisk` to query from disk cache only; `SDImageCacheTypeMemory` to query from memory only. And `SDImageCacheTypeAll` to query from both memory cache and disk cache. Specify `SDImageCacheTypeNone` is invalid and totally ignore the cache query. If not provide or the value is invalid, we will use `SDImageCacheTypeAll`. (NSNumber) */ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextQueryCacheType; diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index ba61529f..305caf3c 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -294,6 +294,29 @@ [self waitForExpectationsWithCommonTimeout]; } +- (void)test15ThatQueryCacheTypeWork { + XCTestExpectation *expectation = [self expectationWithDescription:@"Image query cache type works"]; + NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/101x101.png"]; + NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:url]; + NSData *testImageData = [NSData dataWithContentsOfFile:[self testJPEGPath]]; + [SDImageCache.sharedImageCache storeImageDataToDisk:testImageData forKey:key]; + + // Query memory first + [SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageFromCacheOnly context:@{SDWebImageContextQueryCacheType : @(SDImageCacheTypeMemory)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + expect(image).beNil(); + expect(cacheType).equal(SDImageCacheTypeNone); + // Query disk secondly + [SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageFromCacheOnly context:@{SDWebImageContextQueryCacheType : @(SDImageCacheTypeDisk)} progress:nil completed:^(UIImage * _Nullable image2, NSData * _Nullable data2, NSError * _Nullable error2, SDImageCacheType cacheType2, BOOL finished2, NSURL * _Nullable imageURL2) { + expect(image2).notTo.beNil(); + expect(cacheType2).equal(SDImageCacheTypeDisk); + [SDImageCache.sharedImageCache removeImageFromDiskForKey:key]; + [expectation fulfill]; + }]; + }]; + + [self waitForExpectationsWithCommonTimeout]; +} + - (NSString *)testJPEGPath { NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; return [testBundle pathForResource:@"TestImage" ofType:@"jpg"]; diff --git a/Tests/Tests/SDWebImageTestCache.m b/Tests/Tests/SDWebImageTestCache.m index d9e34e3d..762a2d9a 100644 --- a/Tests/Tests/SDWebImageTestCache.m +++ b/Tests/Tests/SDWebImageTestCache.m @@ -188,6 +188,7 @@ static NSString * const SDWebImageTestDiskCacheExtendedAttributeName = @"com.hac } else if ([self.diskCache containsDataForKey:key]) { containsCacheType = SDImageCacheTypeDisk; } + break; default: break; }