mirror of
https://github.com/status-im/react-native.git
synced 2025-02-04 21:53:30 +00:00
Plug in the Cache to the ImageLoader
Reviewed By: donyu Differential Revision: D3586563 fbshipit-source-id: 03f457df97066a522dc923b5f432314da40f7d71
This commit is contained in:
parent
54244e15bf
commit
ddc70ffd85
@ -199,7 +199,6 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
* Provides an interface to use for providing a image caching strategy.
|
||||
*/
|
||||
|
@ -17,20 +17,12 @@
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTImageCache.h"
|
||||
#import "RCTImageUtils.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTNetworking.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 1024 * 1024; // 1MB
|
||||
|
||||
static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat scale,
|
||||
RCTResizeMode resizeMode, NSString *responseDate)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@|%g|%g|%g|%zd|%@",
|
||||
imageTag, size.width, size.height, scale, resizeMode, responseDate];
|
||||
}
|
||||
|
||||
@implementation UIImage (React)
|
||||
|
||||
- (CAKeyframeAnimation *)reactKeyframeAnimation
|
||||
@ -51,7 +43,7 @@ static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat sc
|
||||
NSArray<id<RCTImageDataDecoder>> *_decoders;
|
||||
NSOperationQueue *_imageDecodeQueue;
|
||||
dispatch_queue_t _URLRequestQueue;
|
||||
NSCache *_decodedImageCache;
|
||||
id<RCTImageCacheDelegate> _imageCache;
|
||||
NSMutableArray *_pendingTasks;
|
||||
NSInteger _activeTasks;
|
||||
NSMutableArray *_pendingDecodes;
|
||||
@ -71,18 +63,15 @@ RCT_EXPORT_MODULE()
|
||||
_maxConcurrentDecodingBytes = _maxConcurrentDecodingBytes ?: 30 * 1024 * 1024; // 30MB
|
||||
|
||||
_URLRequestQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLRequestQueue", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
_decodedImageCache = [NSCache new];
|
||||
_decodedImageCache.totalCostLimit = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
// Clear cache in the event of a memory warning, or if app enters background
|
||||
[[NSNotificationCenter defaultCenter] addObserver:_decodedImageCache selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:_decodedImageCache selector:@selector(removeAllObjects) name:UIApplicationWillResignActiveNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
- (id<RCTImageCacheDelegate>)getImageCache
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:_decodedImageCache];
|
||||
if (!_imageCache) {
|
||||
//set up with default cache
|
||||
_imageCache = [RCTImageCache new];
|
||||
}
|
||||
return _imageCache;
|
||||
}
|
||||
|
||||
- (float)handlerPriority
|
||||
@ -295,7 +284,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
|
||||
completionBlock:(void (^)(NSError *error, id imageOrData, NSString *cacheKey))completionBlock
|
||||
completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate))completionBlock
|
||||
{
|
||||
__block volatile uint32_t cancelled = 0;
|
||||
__block dispatch_block_t cancelLoad = nil;
|
||||
@ -324,19 +313,16 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
[loadHandler shouldCacheLoadedImages] : YES;
|
||||
// If we've received an image, we should try to set it synchronously,
|
||||
// if it's data, do decoding on a background thread.
|
||||
NSString *cacheKey = cacheResult ?
|
||||
RCTCacheKeyForImage(request.URL.absoluteString, size, scale, resizeMode, fetchDate) : nil;
|
||||
|
||||
if (RCTIsMainQueue() && ![imageOrData isKindOfClass:[UIImage class]]) {
|
||||
// Most loaders do not return on the main thread, so caller is probably not
|
||||
// expecting it, and may do expensive post-processing in the callback
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if (!cancelled) {
|
||||
completionBlock(error, imageOrData, cacheKey);
|
||||
completionBlock(error, imageOrData, cacheResult, fetchDate);
|
||||
}
|
||||
});
|
||||
} else if (!cancelled) {
|
||||
completionBlock(error, imageOrData, cacheKey);
|
||||
completionBlock(error, imageOrData, cacheResult, fetchDate);
|
||||
}
|
||||
};
|
||||
|
||||
@ -501,7 +487,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
__block void(^cancelLoad)(void) = nil;
|
||||
__weak RCTImageLoader *weakSelf = self;
|
||||
|
||||
void (^completionHandler)(NSError *, id, NSString *) = ^(NSError *error, id imageOrData, NSString *cacheKey) {
|
||||
void (^completionHandler)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
|
||||
__typeof(self) strongSelf = weakSelf;
|
||||
if (cancelled || !strongSelf) {
|
||||
return;
|
||||
@ -513,8 +499,12 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
}
|
||||
|
||||
// Check decoded image cache
|
||||
if (cacheKey) {
|
||||
UIImage *image = [strongSelf->_decodedImageCache objectForKey:cacheKey];
|
||||
if (cacheResult) {
|
||||
UIImage *image = [[strongSelf getImageCache] imageForUrl:imageURLRequest.URL.absoluteString
|
||||
size:size
|
||||
scale:scale
|
||||
resizeMode:resizeMode
|
||||
responseDate:fetchDate];
|
||||
if (image) {
|
||||
completionBlock(nil, image);
|
||||
return;
|
||||
@ -524,10 +514,12 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
// Store decoded image in cache
|
||||
RCTImageLoaderCompletionBlock cacheResultHandler = ^(NSError *error_, UIImage *image) {
|
||||
if (image) {
|
||||
CGFloat bytes = image.size.width * image.size.height * image.scale * image.scale * 4;
|
||||
if (bytes <= RCTMaxCachableDecodedImageSizeInBytes) {
|
||||
[self->_decodedImageCache setObject:image forKey:cacheKey cost:bytes];
|
||||
}
|
||||
[[strongSelf getImageCache] addImageToCache:image
|
||||
URL:imageURLRequest.URL.absoluteString
|
||||
size:size
|
||||
scale:scale
|
||||
resizeMode:resizeMode
|
||||
responseDate:fetchDate];
|
||||
}
|
||||
|
||||
completionBlock(error_, image);
|
||||
@ -538,7 +530,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
scale:scale
|
||||
clipped:clipped
|
||||
resizeMode:resizeMode
|
||||
completionBlock:cacheKey ? cacheResultHandler: completionBlock];
|
||||
completionBlock:cacheResult ? cacheResultHandler: completionBlock];
|
||||
};
|
||||
|
||||
cancelLoad = [self _loadImageOrDataWithURLRequest:imageURLRequest
|
||||
@ -664,7 +656,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
|
||||
block:(void(^)(NSError *error, CGSize size))callback
|
||||
{
|
||||
void (^completion)(NSError *, id, NSString *) = ^(NSError *error, id imageOrData, NSString *cacheKey) {
|
||||
void (^completion)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
|
||||
CGSize size;
|
||||
if ([imageOrData isKindOfClass:[NSData class]]) {
|
||||
NSDictionary *meta = RCTGetImageMetadata(imageOrData);
|
||||
|
Loading…
x
Reference in New Issue
Block a user