Merge pull request #3466 from dreampiggy/feat/encode_options

Added `SDWebImageContextImageEncodeOptions` to pass encode options like compression quality to SDImageCache storeImage API. Seperate the SDImageCache encode queue and IO queue to match waitStoreCache behavior
This commit is contained in:
DreamPiggy 2023-01-12 16:35:50 +08:00 committed by GitHub
commit 7c63bad41c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 126 deletions

View File

@ -220,7 +220,7 @@ static NSString * _defaultDiskCacheDirectory;
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
return [self storeImage:image imageData:imageData forKey:key options:0 context:nil cacheType:(toDisk ? SDImageCacheTypeDisk : SDImageCacheTypeMemory) completion:completionBlock];
[self storeImage:image imageData:imageData forKey:key options:0 context:nil cacheType:(toDisk ? SDImageCacheTypeAll : SDImageCacheTypeMemory) completion:completionBlock];
}
- (void)storeImage:(nullable UIImage *)image
@ -250,38 +250,47 @@ static NSString * _defaultDiskCacheDirectory;
}
return;
}
NSData *data = imageData;
if (!data && [image respondsToSelector:@selector(animatedImageData)]) {
// If image is custom animated image class, prefer its original animated data
data = [((id<SDAnimatedImage>)image) animatedImageData];
}
SDCallbackQueue *queue = context[SDWebImageContextCallbackQueue];
dispatch_async(self.ioQueue, ^{
@autoreleasepool {
NSData *data = imageData;
if (!data && [image respondsToSelector:@selector(animatedImageData)]) {
// If image is custom animated image class, prefer its original animated data
data = [((id<SDAnimatedImage>)image) animatedImageData];
}
if (!data && image) {
// Check image's associated image format, may return .undefined
SDImageFormat format = image.sd_imageFormat;
if (format == SDImageFormatUndefined) {
// If image is animated, use GIF (APNG may be better, but has bugs before macOS 10.14)
if (image.sd_isAnimated) {
format = SDImageFormatGIF;
} else {
// If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format
format = [SDImageCoderHelper CGImageContainsAlpha:image.CGImage] ? SDImageFormatPNG : SDImageFormatJPEG;
}
if (!data && image) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Check image's associated image format, may return .undefined
SDImageFormat format = image.sd_imageFormat;
if (format == SDImageFormatUndefined) {
// If image is animated, use GIF (APNG may be better, but has bugs before macOS 10.14)
if (image.sd_isAnimated) {
format = SDImageFormatGIF;
} else {
// If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format
format = [SDImageCoderHelper CGImageContainsAlpha:image.CGImage] ? SDImageFormatPNG : SDImageFormatJPEG;
}
data = [[SDImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil];
}
NSData *data = [[SDImageCodersManager sharedManager] encodedDataWithImage:image format:format options:context[SDWebImageContextImageEncodeOptions]];
dispatch_async(self.ioQueue, ^{
[self _storeImageDataToDisk:data forKey:key];
[self _archivedDataWithImage:image forKey:key];
if (completionBlock) {
[(queue ?: SDCallbackQueue.mainQueue) async:^{
completionBlock();
}];
}
});
});
} else {
dispatch_async(self.ioQueue, ^{
[self _storeImageDataToDisk:data forKey:key];
[self _archivedDataWithImage:image forKey:key];
}
if (completionBlock) {
[(queue ?: SDCallbackQueue.mainQueue) async:^{
completionBlock();
}];
}
});
if (completionBlock) {
[(queue ?: SDCallbackQueue.mainQueue) async:^{
completionBlock();
}];
}
});
}
}
- (void)_archivedDataWithImage:(UIImage *)image forKey:(NSString *)key {

View File

@ -122,7 +122,7 @@ FOUNDATION_EXPORT void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _N
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock API_DEPRECATED_WITH_REPLACEMENT("storeImage:imageData:forKey:options:context:cacheType:completion:", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));;
completion:(nullable SDWebImageNoParamsBlock)completionBlock API_DEPRECATED_WITH_REPLACEMENT("storeImage:imageData:forKey:options:context:cacheType:completion:", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
@optional
/**
@ -144,7 +144,7 @@ FOUNDATION_EXPORT void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _N
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
@required
#pragma mark - Deprecated because SDWebImageManager does not use these APIs
/**
Remove the image from image cache for the given key. If cache type is memory only, completion is called synchronously, else asynchronously.
@ -154,7 +154,7 @@ FOUNDATION_EXPORT void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _N
*/
- (void)removeImageForKey:(nullable NSString *)key
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
completion:(nullable SDWebImageNoParamsBlock)completionBlock API_DEPRECATED("No longer use. Cast to cache instance and call its API", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
/**
Check if image cache contains the image for the given key (does not load the image). If image is cached in memory, completion is called synchronously, else asynchronously.
@ -165,7 +165,7 @@ FOUNDATION_EXPORT void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _N
*/
- (void)containsImageForKey:(nullable NSString *)key
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock;
completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock API_DEPRECATED("No longer use. Cast to cache instance and call its API", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
/**
Clear all the cached images for image cache. If cache type is memory only, completion is called synchronously, else asynchronously.
@ -174,6 +174,6 @@ FOUNDATION_EXPORT void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _N
@param completionBlock A block executed after the operation is finished
*/
- (void)clearWithCacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
completion:(nullable SDWebImageNoParamsBlock)completionBlock API_DEPRECATED("No longer use. Cast to cache instance and call its API", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
@end

View File

@ -295,6 +295,13 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageT
#pragma mark - Cache Context Options
/**
A Dictionary (SDImageCoderOptions) value, which pass the extra encode options to the SDImageCoder. Introduced in SDWebImage 5.15.0
You can pass encode options like `compressionQuality`, `maxFileSize`, `maxPixelSize` to control the encoding related thing, this is used inside `SDImageCache` during store logic.
@note For developer who use custom cache protocol (not SDImageCache instance), they need to upgrade and use these options for encoding.
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageEncodeOptions;
/**
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)

View File

@ -137,6 +137,7 @@ SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFa
SDWebImageContextOption const SDWebImageContextImagePreserveAspectRatio = @"imagePreserveAspectRatio";
SDWebImageContextOption const SDWebImageContextImageThumbnailPixelSize = @"imageThumbnailPixelSize";
SDWebImageContextOption const SDWebImageContextImageTypeIdentifierHint = @"imageTypeIdentifierHint";
SDWebImageContextOption const SDWebImageContextImageEncodeOptions = @"imageEncodeOptions";
SDWebImageContextOption const SDWebImageContextQueryCacheType = @"queryCacheType";
SDWebImageContextOption const SDWebImageContextStoreCacheType = @"storeCacheType";
SDWebImageContextOption const SDWebImageContextOriginalQueryCacheType = @"originalQueryCacheType";

View File

@ -499,18 +499,16 @@ static id<SDImageLoader> _defaultImageLoader;
}
if (shouldTransformImage) {
// transformed cache key
NSString *key = [self cacheKeyForURL:url context:context];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
@autoreleasepool {
// transformed cache key
NSString *key = [self cacheKeyForURL:url context:context];
// Case that transformer on thumbnail, which this time need full pixel image
UIImage *transformedImage = [transformer transformedImageWithImage:cacheImage forKey:key];
if (transformedImage) {
transformedImage.sd_isTransformed = YES;
[self callStoreOriginCacheProcessForOperation:operation url:url options:options context:context originalImage:originalImage cacheImage:transformedImage originalData:originalData cacheData:nil cacheType:cacheType finished:finished completed:completedBlock];
} else {
[self callStoreOriginCacheProcessForOperation:operation url:url options:options context:context originalImage:originalImage cacheImage:cacheImage originalData:originalData cacheData:cacheData cacheType:cacheType finished:finished completed:completedBlock];
}
// Case that transformer on thumbnail, which this time need full pixel image
UIImage *transformedImage = [transformer transformedImageWithImage:cacheImage forKey:key];
if (transformedImage) {
transformedImage.sd_isTransformed = YES;
[self callStoreOriginCacheProcessForOperation:operation url:url options:options context:context originalImage:originalImage cacheImage:transformedImage originalData:originalData cacheData:nil cacheType:cacheType finished:finished completed:completedBlock];
} else {
[self callStoreOriginCacheProcessForOperation:operation url:url options:options context:context originalImage:originalImage cacheImage:cacheImage originalData:originalData cacheData:cacheData cacheType:cacheType finished:finished completed:completedBlock];
}
});
} else {
@ -557,14 +555,12 @@ static id<SDImageLoader> _defaultImageLoader;
NSString *key = [self originalCacheKeyForURL:url context:context];
if (finished && cacheSerializer && (originalStoreCacheType == SDImageCacheTypeDisk || originalStoreCacheType == SDImageCacheTypeAll)) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
@autoreleasepool {
NSData *newOriginalData = [cacheSerializer cacheDataWithImage:originalImage originalData:originalData imageURL:url];
// Store original image and data
[self storeImage:originalImage imageData:newOriginalData forKey:key options:options context:context imageCache:imageCache cacheType:originalStoreCacheType finished:finished completion:^{
// Continue store cache process, transformed data is nil
[self callStoreCacheProcessForOperation:operation url:url options:options context:context image:cacheImage data:cacheData cacheType:cacheType finished:finished completed:completedBlock];
}];
}
NSData *newOriginalData = [cacheSerializer cacheDataWithImage:originalImage originalData:originalData imageURL:url];
// Store original image and data
[self storeImage:originalImage imageData:newOriginalData forKey:key options:options context:context imageCache:imageCache cacheType:originalStoreCacheType finished:finished completion:^{
// Continue store cache process, transformed data is nil
[self callStoreCacheProcessForOperation:operation url:url options:options context:context image:cacheImage data:cacheData cacheType:cacheType finished:finished completed:completedBlock];
}];
});
} else {
// Store original image and data

View File

@ -36,20 +36,21 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png";
- (void)test04ClearDiskCache{
XCTestExpectation *expectation = [self expectationWithDescription:@"Clear disk cache"];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (!isInCache) {
[[SDImageCache sharedImageCache] calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) {
expect(fileCount).to.equal(0);
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (!isInCache) {
[[SDImageCache sharedImageCache] calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) {
expect(fileCount).to.equal(0);
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
}];
} else {
XCTFail(@"Image should not be in cache");
}
} else {
XCTFail(@"Image should not be in cache");
}
}];
}];
}];
[self waitForExpectationsWithCommonTimeout];
@ -79,17 +80,22 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png";
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey"];
UIImage *image = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
XCTFail(@"Image should be in cache");
}
[[SDImageCache sharedImageCache] removeImageFromDiskForKey:kTestImageKeyJPEG];
[[SDImageCache sharedImageCache] removeImageFromMemoryForKey:kTestImageKeyJPEG];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG completion:^{
// Disk cache store in async
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
XCTFail(@"Image should be in cache");
}
}];
}];
// Memory cache store in sync
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image);
[self waitForExpectationsWithCommonTimeout];
}
@ -98,17 +104,20 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png";
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=YES"];
UIImage *image = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:YES completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
XCTFail(@"Image should be in cache");
}
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:YES completion:^{
// Disk cache store in async
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
XCTFail(@"Image should be in cache");
}
}];
}];
// Memory cache store in sync
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image);
[self waitForExpectationsWithCommonTimeout];
}
@ -116,16 +125,20 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png";
- (void)test08InsertionOfImageOnlyInMemory {
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=NO"];
UIImage *image = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:NO completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (!isInCache) {
[expectation fulfill];
} else {
XCTFail(@"Image should not be in cache");
}
[[SDImageCache sharedImageCache] removeImageFromDiskForKey:kTestImageKeyJPEG];
[[SDImageCache sharedImageCache] removeImageFromMemoryForKey:kTestImageKeyJPEG];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:NO completion:^{
// Disk cache store in async
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (!isInCache) {
[expectation fulfill];
} else {
XCTFail(@"Image should not be in cache");
}
}];
}];
// Memory cache store in sync
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]);
[[SDImageCache sharedImageCache] storeImageToMemory:image forKey:kTestImageKeyJPEG];
[[SDImageCache sharedImageCache] clearMemory];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil();
@ -135,46 +148,50 @@ static NSString *kTestImageKeyPNG = @"TestImageKey.png";
- (void)test09RetrieveImageThroughNSOperation {
XCTestExpectation *expectation = [self expectationWithDescription:@"queryCacheOperationForKey"];
UIImage *imageForTesting = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:imageForTesting forKey:kTestImageKeyJPEG completion:nil];
id<SDWebImageOperation> operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:kTestImageKeyJPEG done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
expect(image).to.equal(imageForTesting);
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
[[SDImageCache sharedImageCache] storeImage:imageForTesting forKey:kTestImageKeyJPEG completion:^{
id<SDWebImageOperation> operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:kTestImageKeyJPEG done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
expect(image).to.equal(imageForTesting);
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
expect(operation).toNot.beNil;
}];
expect(operation).toNot.beNil;
[self waitForExpectationsWithCommonTimeout];
}
- (void)test10RemoveImageForKeyWithCompletion {
XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey"];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test11RemoveImageforKeyNotFromDiskWithCompletion{
XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey fromDisk:NO"];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:NO withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).toNot.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:NO withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).toNot.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test12RemoveImageforKeyFromDiskWithCompletion{
XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey fromDisk:YES"];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:YES withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:YES withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}

View File

@ -132,17 +132,31 @@
- (void)test08ThatImageTransformerWork {
XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"];
NSURL *url = [NSURL URLWithString:kTestJPEGURL];
NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/80x60.png"];
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:[SDImageCache sharedImageCache] loader:[SDWebImageDownloader sharedDownloader]];
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Transformer"];
SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:cache loader:SDWebImageDownloader.sharedDownloader];
NSString *key = [manager cacheKeyForURL:url];
NSString *transformedKey = [manager cacheKeyForURL:url context:@{SDWebImageContextImageTransformer : transformer}];
manager.transformer = transformer;
[[SDImageCache sharedImageCache] removeImageForKey:kTestJPEGURL withCompletion:^{
[manager loadImageWithURL:url options:SDWebImageTransformAnimatedImage | SDWebImageTransformVectorImage progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
expect(image).equal(transformer.testImage);
[expectation fulfill];
}];
[cache removeImageFromDiskForKey:key];
[cache removeImageFromMemoryForKey:key];
[cache removeImageFromDiskForKey:transformedKey];
[cache removeImageFromMemoryForKey:transformedKey];
// Test encode options with transformer (because data is not available)
SDImageCoderOptions *encodeOptions = @{SDImageCoderEncodeMaxPixelSize : @(CGSizeMake(40, 30))};
[manager loadImageWithURL:url options:SDWebImageTransformAnimatedImage | SDWebImageTransformVectorImage | SDWebImageWaitStoreCache context:@{SDWebImageContextImageEncodeOptions : encodeOptions} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
expect(image).equal(transformer.testImage);
// Query the encoded data again
NSData *encodedData = [cache diskImageDataForKey:transformedKey];
UIImage *encodedImage = [UIImage sd_imageWithData:encodedData];
CGSize encodedImageSize = encodedImage.size;
expect(encodedImageSize.width).equal(40);
expect(encodedImageSize.height).equal(30);
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
@ -375,7 +389,11 @@
NSString *originalKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
NSString *transformedKey = [SDWebImageManager.sharedManager cacheKeyForURL:url context:@{SDWebImageContextImageTransformer : transformer}];
[[SDWebImageManager sharedManager] loadImageWithURL:url options:0 context:@{SDWebImageContextImageTransformer : transformer, SDWebImageContextOriginalStoreCacheType : @(SDImageCacheTypeAll)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
[[SDImageCache sharedImageCache] removeImageFromDiskForKey:originalKey];
[[SDImageCache sharedImageCache] removeImageFromMemoryForKey:originalKey];
[[SDImageCache sharedImageCache] removeImageFromDiskForKey:transformedKey];
[[SDImageCache sharedImageCache] removeImageFromMemoryForKey:transformedKey];
[[SDWebImageManager sharedManager] loadImageWithURL:url options:SDWebImageWaitStoreCache context:@{SDWebImageContextImageTransformer : transformer, SDWebImageContextOriginalStoreCacheType : @(SDImageCacheTypeAll)} 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 memory/disk cache
@ -386,7 +404,7 @@
expect(image).equal(transformedImage);
[SDImageCache.sharedImageCache removeImageFromDiskForKey:transformedKey];
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:transformedKey];
[SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageFromCacheOnly context:@{SDWebImageContextImageTransformer : transformer, SDWebImageContextOriginalQueryCacheType : @(SDImageCacheTypeAll)} progress:nil completed:^(UIImage * _Nullable image2, NSData * _Nullable data2, NSError * _Nullable error2, SDImageCacheType cacheType2, BOOL finished2, NSURL * _Nullable imageURL2) {
[SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageWaitStoreCache | SDWebImageFromCacheOnly context:@{SDWebImageContextImageTransformer : transformer, SDWebImageContextOriginalQueryCacheType : @(SDImageCacheTypeAll)} progress:nil completed:^(UIImage * _Nullable image2, NSData * _Nullable data2, NSError * _Nullable error2, SDImageCacheType cacheType2, BOOL finished2, NSURL * _Nullable imageURL2) {
// Get the transformed image
expect(image2).equal(transformer.testImage);
expect(data).beNil(); // Currently, the thumbnailed and transformed image always data is nil, to avoid confuse user (the image and data represent no longer match)
@ -496,7 +514,7 @@
NSString *thumbnailKey = SDThumbnailedKeyForKey(fullSizeKey, thumbnailSize, YES);
[SDImageCache.sharedImageCache removeImageFromDiskForKey:thumbnailKey];
// Load with thumbnail, should use full size cache instead to decode and scale down
[SDWebImageManager.sharedManager loadImageWithURL:url options:0 context:@{SDWebImageContextImageThumbnailPixelSize : @(thumbnailSize)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
[SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageWaitStoreCache context:@{SDWebImageContextImageThumbnailPixelSize : @(thumbnailSize)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
expect(image.size).equal(thumbnailSize);
expect(data).beNil(); // Currently, the thumbnailed and transformed image always data is nil, to avoid confuse user (the image and data represent no longer match)
expect(cacheType).equal(SDImageCacheTypeDisk);
@ -584,7 +602,7 @@
};
NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:url context:context]; // Thumbnail key
[SDImageCache.sharedImageCache removeImageFromDiskForKey:key];
[SDWebImageManager.sharedManager loadImageWithURL:url options:0 context:context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
[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(cacheType).equal(SDImageCacheTypeDisk);
expect(data).beNil(); // Currently, the thumbnailed and transformed image always data is nil, to avoid confuse user (the image and data represent no longer match)
expect(image.size.width).equal(100);