Add a query cache options to allow some specify logic.

Currently is used for FLAnimatedImage
This commit is contained in:
DreamPiggy 2018-01-09 18:20:23 +08:00
parent 261a1dc2d6
commit 9420a20f3f
6 changed files with 81 additions and 30 deletions

View File

@ -46,8 +46,10 @@
options:(SDWebImageOptions)options options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock { completed:(nullable SDExternalCompletionBlock)completedBlock {
__weak typeof(self)weakSelf = self; options |= SDWebImageQueryDiskDataWhenInMemory;
options |= SDWebImageQueryDiskDataSync;
dispatch_group_t group = dispatch_group_create(); dispatch_group_t group = dispatch_group_create();
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url [self sd_internalSetImageWithURL:url
placeholderImage:placeholder placeholderImage:placeholder
options:options options:options

View File

@ -25,6 +25,17 @@ typedef NS_ENUM(NSInteger, SDImageCacheType) {
SDImageCacheTypeMemory SDImageCacheTypeMemory
}; };
typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
/**
* By default, we do not query disk cache when the image is cached in memory. This mask can force query disk data at the same time.
*/
SDImageCacheQueryDiskDataWhenInMemory = 1 << 0,
/**
* By default, we query the memory cache synchonized, disk cache asynchronized. This mask can force to query disk cache synchonized.
*/
SDImageCacheQueryDiskDataSync = 1 << 1
};
typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType);
typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache);
@ -166,6 +177,17 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot
*/ */
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock; - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock;
/**
* Asynchronously queries the cache with operation and call the completion when done.
*
* @param key The unique key used to store the wanted image
* @param options A mask to specify options to use for this cache query
* @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 done:(nullable SDCacheQueryCompletedBlock)doneBlock;
/** /**
* Query the memory cache synchronously. * Query the memory cache synchronously.
* *

View File

@ -322,6 +322,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key { - (nullable UIImage *)diskImageForKey:(nullable NSString *)key {
NSData *data = [self diskImageDataBySearchingAllPathsForKey:key]; NSData *data = [self diskImageDataBySearchingAllPathsForKey:key];
return [self diskImageForKey:key data:data];
}
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data {
if (data) { if (data) {
UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data]; UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data];
image = [self scaledImageForKey:key image:image]; image = [self scaledImageForKey:key image:image];
@ -338,50 +342,64 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
return SDScaledImageForKey(key, image); return SDScaledImageForKey(key, image);
} }
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock { - (NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock {
return [self queryCacheOperationForKey:key options:0 done:doneBlock];
}
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock {
if (!key) { if (!key) {
if (doneBlock) { if (doneBlock) {
doneBlock(nil, nil, SDImageCacheTypeNone); doneBlock(nil, nil, SDImageCacheTypeNone);
} }
return nil; return nil;
} }
// First check the in-memory cache... // First check the in-memory cache...
UIImage *image = [self imageFromMemoryCacheForKey:key]; UIImage *image = [self imageFromMemoryCacheForKey:key];
if (image) { if (image && !(options & SDImageCacheQueryDiskDataWhenInMemory)) {
NSData *diskData = nil;
if (image.images) {
diskData = [self diskImageDataBySearchingAllPathsForKey:key];
}
if (doneBlock) { if (doneBlock) {
doneBlock(image, diskData, SDImageCacheTypeMemory); doneBlock(image, nil, SDImageCacheTypeMemory);
} }
return nil; return nil;
} }
NSOperation *operation = [NSOperation new]; NSOperation *operation = [NSOperation new];
dispatch_async(self.ioQueue, ^{ void(^queryDiskBlock)(void) = ^{
if (operation.isCancelled) { if (operation.isCancelled) {
// do not call the completion if cancelled // do not call the completion if cancelled
return; return;
} }
@autoreleasepool { @autoreleasepool {
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key]; NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
UIImage *diskImage = [self diskImageForKey:key]; UIImage *diskImage = image;
if (diskImage && self.config.shouldCacheImagesInMemory) { if (!diskImage && diskData) {
NSUInteger cost = SDCacheCostForImage(diskImage); // decode image data only if in-memory cache missed
[self.memCache setObject:diskImage forKey:key cost:cost]; diskImage = [self diskImageForKey:key data:diskData];
if (diskImage && self.config.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost];
}
} }
if (doneBlock) { if (doneBlock) {
dispatch_async(dispatch_get_main_queue(), ^{ if (options & SDImageCacheQueryDiskDataSync) {
doneBlock(diskImage, diskData, SDImageCacheTypeDisk); doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
}); } else {
dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
});
}
} }
} }
}); };
if (options & SDImageCacheQueryDiskDataSync) {
queryDiskBlock();
} else {
dispatch_async(self.ioQueue, queryDiskBlock);
}
return operation; return operation;
} }

View File

@ -105,13 +105,6 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return nil; return nil;
} }
SDImageFormat format = [NSData sd_imageFormatForImageData:data];
if (format == SDImageFormatGIF) {
// static single GIF need to be created animated for `FLAnimatedImage` logic
// GIF does not support EXIF image orientation
image = [UIImage animatedImageWithImages:@[image] duration:image.duration];
return image;
}
UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data]; UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data];
if (orientation != UIImageOrientationUp) { if (orientation != UIImageOrientationUp) {
image = [UIImage imageWithCGImage:image.CGImage image = [UIImage imageWithCGImage:image.CGImage

View File

@ -94,7 +94,19 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
* images to a size compatible with the constrained memory of devices. * images to a size compatible with the constrained memory of devices.
* If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated. * If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated.
*/ */
SDWebImageScaleDownLargeImages = 1 << 12 SDWebImageScaleDownLargeImages = 1 << 12,
/**
* By default, we do not query disk cache when the image is cached in memory. This mask can force query disk data at the same time.
* This options is recommend to be used with `SDWebImageQueryDiskDataSync` to ensure the image is loaded in the same runloop.
*/
SDWebImageQueryDiskDataWhenInMemory = 1 << 13,
/**
* By default, we query the memory cache synchonized, disk cache asynchronized. This mask can force to query disk cache synchonized to ensure that image is loaded in the same runloop.
* This can avoid flashing during cell reuse if you disable memory cache or in some other cases.
*/
SDWebImageQueryDiskDataSync = 1 << 14
}; };
typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL);

View File

@ -143,8 +143,12 @@
[self.runningOperations addObject:operation]; [self.runningOperations addObject:operation];
} }
NSString *key = [self cacheKeyForURL:url]; NSString *key = [self cacheKeyForURL:url];
SDImageCacheOptions cacheOptions = 0;
if (options & SDWebImageQueryDiskDataWhenInMemory) cacheOptions |= SDImageCacheQueryDiskDataWhenInMemory;
if (options & SDWebImageQueryDiskDataSync) cacheOptions |= SDImageCacheQueryDiskDataSync;
operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) {
if (operation.isCancelled) { if (operation.isCancelled) {
[self safelyRemoveOperationFromRunning:operation]; [self safelyRemoveOperationFromRunning:operation];
return; return;