From 8445f2b1a702678b9831be1cc9c3c76b701555ec Mon Sep 17 00:00:00 2001 From: soondl Date: Sun, 20 Feb 2022 16:08:40 +0900 Subject: [PATCH 1/2] Fix imageView blinks with option 'SDImageCacheQueryDiskDataSync' --- SDWebImage/Core/SDImageCache.m | 77 +++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/SDWebImage/Core/SDImageCache.m b/SDWebImage/Core/SDImageCache.m index adb886db..635908b3 100644 --- a/SDWebImage/Core/SDImageCache.m +++ b/SDWebImage/Core/SDImageCache.m @@ -552,51 +552,60 @@ static NSString * _defaultDiskCacheDirectory; // 2. in-memory cache miss & diskDataSync BOOL shouldQueryDiskSync = ((image && options & SDImageCacheQueryMemoryDataSync) || (!image && options & SDImageCacheQueryDiskDataSync)); - void(^queryDiskBlock)(void) = ^{ + NSData* (^queryDiskDataBlock)(void) = ^NSData* { if (operation.isCancelled) { - if (doneBlock) { - doneBlock(nil, nil, SDImageCacheTypeNone); - } - return; + return nil; } - @autoreleasepool { - NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key]; - UIImage *diskImage; - if (image) { - // the image is from in-memory cache, but need image data - diskImage = image; - } else if (diskData) { - BOOL shouldCacheToMomery = YES; - if (context[SDWebImageContextStoreCacheType]) { - SDImageCacheType cacheType = [context[SDWebImageContextStoreCacheType] integerValue]; - shouldCacheToMomery = (cacheType == SDImageCacheTypeAll || cacheType == SDImageCacheTypeMemory); - } - // decode image data only if in-memory cache missed - diskImage = [self diskImageForKey:key data:diskData options:options context:context]; - if (shouldCacheToMomery && diskImage && self.config.shouldCacheImagesInMemory) { - NSUInteger cost = diskImage.sd_memoryCost; - [self.memoryCache setObject:diskImage forKey:key cost:cost]; - } + return [self diskImageDataBySearchingAllPathsForKey:key]; + }; + + UIImage* (^queryDiskImageBlock)(NSData*) = ^UIImage*(NSData* diskData) { + if (operation.isCancelled) { + return nil; + } + + UIImage *diskImage; + if (image) { + // the image is from in-memory cache, but need image data + diskImage = image; + } else if (diskData) { + BOOL shouldCacheToMomery = YES; + if (context[SDWebImageContextStoreCacheType]) { + SDImageCacheType cacheType = [context[SDWebImageContextStoreCacheType] integerValue]; + shouldCacheToMomery = (cacheType == SDImageCacheTypeAll || cacheType == SDImageCacheTypeMemory); } - - if (doneBlock) { - if (shouldQueryDiskSync) { - doneBlock(diskImage, diskData, SDImageCacheTypeDisk); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - doneBlock(diskImage, diskData, SDImageCacheTypeDisk); - }); - } + // decode image data only if in-memory cache missed + diskImage = [self diskImageForKey:key data:diskData options:options context:context]; + if (shouldCacheToMomery && diskImage && self.config.shouldCacheImagesInMemory) { + NSUInteger cost = diskImage.sd_memoryCost; + [self.memoryCache setObject:diskImage forKey:key cost:cost]; } } + return diskImage; }; // Query in ioQueue to keep IO-safe if (shouldQueryDiskSync) { - dispatch_sync(self.ioQueue, queryDiskBlock); + __block NSData* diskData; + __block UIImage* diskImage; + dispatch_sync(self.ioQueue, ^{ + diskData = queryDiskDataBlock(); + diskImage = queryDiskImageBlock(diskData); + }); + if (doneBlock) { + doneBlock(diskImage, diskData, SDImageCacheTypeDisk); + } } else { - dispatch_async(self.ioQueue, queryDiskBlock); + dispatch_async(self.ioQueue, ^{ + NSData* diskData = queryDiskDataBlock(); + UIImage* diskImage = queryDiskImageBlock(diskData); + if (doneBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + doneBlock(diskImage, diskData, SDImageCacheTypeDisk); + }); + } + }); } return operation; From 4302777c6f66e713fac20705aa956481a8bb0088 Mon Sep 17 00:00:00 2001 From: soondl Date: Sun, 20 Feb 2022 19:01:12 +0900 Subject: [PATCH 2/2] Add test case `testUIImageViewSetImageWithURLDiskSync` --- Tests/Tests/SDWebCacheCategoriesTests.m | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Tests/Tests/SDWebCacheCategoriesTests.m b/Tests/Tests/SDWebCacheCategoriesTests.m index e8a30596..56f73b31 100644 --- a/Tests/Tests/SDWebCacheCategoriesTests.m +++ b/Tests/Tests/SDWebCacheCategoriesTests.m @@ -35,6 +35,30 @@ [self waitForExpectationsWithCommonTimeout]; } +- (void)testUIImageViewSetImageWithURLDiskSync { + NSData *imageData = [NSData dataWithContentsOfFile:[self testJPEGPath]]; + + // Ensure the image is cached in disk but not memory + [SDImageCache.sharedImageCache removeImageFromMemoryForKey:kTestJPEGURL]; + [SDImageCache.sharedImageCache removeImageFromDiskForKey:kTestJPEGURL]; + [SDImageCache.sharedImageCache storeImageDataToDisk:imageData forKey:kTestJPEGURL]; + + UIImageView *imageView = [[UIImageView alloc] init]; + NSURL *originalImageURL = [NSURL URLWithString:kTestJPEGURL]; + + [imageView sd_setImageWithURL:originalImageURL + placeholderImage:nil + options:SDWebImageQueryDiskDataSync + completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + expect(image).toNot.beNil(); + expect(error).to.beNil(); + expect(originalImageURL).to.equal(imageURL); + expect(imageView.image).to.equal(image); + }]; + expect(imageView.sd_imageURL).equal(originalImageURL); + expect(imageView.image).toNot.beNil(); +} + #if SD_UIKIT - (void)testUIImageViewSetHighlightedImageWithURL { XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setHighlightedImageWithURL"];