Skip to content

Commit 7eeb305

Browse files
committed
Revert [Performance improvement for loading cached images on iOS ]
1 parent 0b4fd62 commit 7eeb305

File tree

3 files changed

+48
-101
lines changed

3 files changed

+48
-101
lines changed

Diff for: Libraries/Image/RCTImageCache.m

+8-60
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,22 @@
2121
static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 2097152; // 2 MB
2222

2323
static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat scale,
24-
RCTResizeMode resizeMode)
24+
RCTResizeMode resizeMode, NSString *responseDate)
2525
{
26-
return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld",
27-
imageTag, size.width, size.height, scale, (long long)resizeMode];
26+
return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld|%@",
27+
imageTag, size.width, size.height, scale, (long long)resizeMode, responseDate];
2828
}
2929

3030
@implementation RCTImageCache
3131
{
3232
NSOperationQueue *_imageDecodeQueue;
3333
NSCache *_decodedImageCache;
34-
NSMutableDictionary *_cacheStaleTimes;
35-
36-
NSDateFormatter *_headerDateFormatter;
3734
}
3835

3936
- (instancetype)init
4037
{
4138
_decodedImageCache = [NSCache new];
4239
_decodedImageCache.totalCostLimit = 20 * 1024 * 1024; // 20 MB
43-
_cacheStaleTimes = [[NSMutableDictionary alloc] init];
4440

4541
[[NSNotificationCenter defaultCenter] addObserver:self
4642
selector:@selector(clearCache)
@@ -50,7 +46,7 @@ - (instancetype)init
5046
selector:@selector(clearCache)
5147
name:UIApplicationWillResignActiveNotification
5248
object:nil];
53-
49+
5450
return self;
5551
}
5652

@@ -62,9 +58,6 @@ - (void)dealloc
6258
- (void)clearCache
6359
{
6460
[_decodedImageCache removeAllObjects];
65-
@synchronized(_cacheStaleTimes) {
66-
[_cacheStaleTimes removeAllObjects];
67-
}
6861
}
6962

7063
- (void)addImageToCache:(UIImage *)image
@@ -85,19 +78,9 @@ - (UIImage *)imageForUrl:(NSString *)url
8578
size:(CGSize)size
8679
scale:(CGFloat)scale
8780
resizeMode:(RCTResizeMode)resizeMode
81+
responseDate:(NSString *)responseDate
8882
{
89-
NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode);
90-
@synchronized(_cacheStaleTimes) {
91-
id staleTime = _cacheStaleTimes[cacheKey];
92-
if (staleTime) {
93-
if ([[NSDate new] compare:(NSDate *)staleTime] == NSOrderedDescending) {
94-
// cached image has expired, clear it out to make room for others
95-
[_cacheStaleTimes removeObjectForKey:cacheKey];
96-
[_decodedImageCache removeObjectForKey:cacheKey];
97-
return nil;
98-
}
99-
}
100-
}
83+
NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode, responseDate);
10184
return [_decodedImageCache objectForKey:cacheKey];
10285
}
10386

@@ -107,44 +90,9 @@ - (void)addImageToCache:(UIImage *)image
10790
scale:(CGFloat)scale
10891
resizeMode:(RCTResizeMode)resizeMode
10992
responseDate:(NSString *)responseDate
110-
cacheControl:(NSString *)cacheControl
11193
{
112-
NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode);
113-
BOOL shouldCache = YES;
114-
NSDate *staleTime;
115-
NSArray<NSString *> *components = [cacheControl componentsSeparatedByString:@","];
116-
for (NSString *component in components) {
117-
if ([component containsString:@"no-cache"] || [component containsString:@"no-store"] || [component hasSuffix:@"max-age=0"]) {
118-
shouldCache = NO;
119-
break;
120-
} else {
121-
NSRange range = [component rangeOfString:@"max-age="];
122-
if (range.location != NSNotFound) {
123-
NSInteger seconds = [[component substringFromIndex:range.location + range.length] integerValue];
124-
NSDate *originalDate = [self dateWithHeaderString:responseDate];
125-
staleTime = [originalDate dateByAddingTimeInterval:(NSTimeInterval)seconds];
126-
}
127-
}
128-
}
129-
if (shouldCache) {
130-
if (staleTime) {
131-
@synchronized(_cacheStaleTimes) {
132-
_cacheStaleTimes[cacheKey] = staleTime;
133-
}
134-
}
135-
return [self addImageToCache:image forKey:cacheKey];
136-
}
137-
}
138-
139-
- (NSDate *)dateWithHeaderString:(NSString *)headerDateString {
140-
if (_headerDateFormatter == nil) {
141-
_headerDateFormatter = [[NSDateFormatter alloc] init];
142-
_headerDateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
143-
_headerDateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
144-
_headerDateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
145-
}
146-
147-
return [_headerDateFormatter dateFromString:headerDateString];
94+
NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode, responseDate);
95+
return [self addImageToCache:image forKey:cacheKey];
14896
}
14997

15098
@end

Diff for: Libraries/Image/RCTImageLoader.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock;
2424
- (UIImage *)imageForUrl:(NSString *)url
2525
size:(CGSize)size
2626
scale:(CGFloat)scale
27-
resizeMode:(RCTResizeMode)resizeMode;
27+
resizeMode:(RCTResizeMode)resizeMode
28+
responseDate:(NSString *)responseDate;
2829

2930
- (void)addImageToCache:(UIImage *)image
3031
URL:(NSString *)url
3132
size:(CGSize)size
3233
scale:(CGFloat)scale
3334
resizeMode:(RCTResizeMode)resizeMode
34-
responseDate:(NSString *)responseDate
35-
cacheControl:(NSString *)cacheControl;
35+
responseDate:(NSString *)responseDate;
3636

3737
@end
3838

Diff for: Libraries/Image/RCTImageLoader.m

+37-38
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
321321
resizeMode:(RCTResizeMode)resizeMode
322322
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
323323
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
324-
completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate, NSString *cacheControl))completionBlock
324+
completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate))completionBlock
325325
{
326326
{
327327
NSMutableURLRequest *mutableRequest = [request mutableCopy];
@@ -344,27 +344,27 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
344344
BOOL requiresScheduling = [loadHandler respondsToSelector:@selector(requiresScheduling)] ?
345345
[loadHandler requiresScheduling] : YES;
346346

347-
BOOL cacheResult = [loadHandler respondsToSelector:@selector(shouldCacheLoadedImages)] ?
348-
[loadHandler shouldCacheLoadedImages] : YES;
349-
350347
__block atomic_bool cancelled = ATOMIC_VAR_INIT(NO);
351348
// TODO: Protect this variable shared between threads.
352349
__block dispatch_block_t cancelLoad = nil;
353-
void (^completionHandler)(NSError *, id, NSString *, NSString *) = ^(NSError *error, id imageOrData, NSString *fetchDate, NSString *cacheControl) {
350+
void (^completionHandler)(NSError *, id, NSString *) = ^(NSError *error, id imageOrData, NSString *fetchDate) {
354351
cancelLoad = nil;
355352

353+
BOOL cacheResult = [loadHandler respondsToSelector:@selector(shouldCacheLoadedImages)] ?
354+
[loadHandler shouldCacheLoadedImages] : YES;
355+
356356
// If we've received an image, we should try to set it synchronously,
357357
// if it's data, do decoding on a background thread.
358358
if (RCTIsMainQueue() && ![imageOrData isKindOfClass:[UIImage class]]) {
359359
// Most loaders do not return on the main thread, so caller is probably not
360360
// expecting it, and may do expensive post-processing in the callback
361361
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
362362
if (!atomic_load(&cancelled)) {
363-
completionBlock(error, imageOrData, cacheResult, fetchDate, cacheControl);
363+
completionBlock(error, imageOrData, cacheResult, fetchDate);
364364
}
365365
});
366366
} else if (!atomic_load(&cancelled)) {
367-
completionBlock(error, imageOrData, cacheResult, fetchDate, cacheControl);
367+
completionBlock(error, imageOrData, cacheResult, fetchDate);
368368
}
369369
};
370370

@@ -378,7 +378,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
378378
progressHandler:progressHandler
379379
partialLoadHandler:partialLoadHandler
380380
completionHandler:^(NSError *error, UIImage *image){
381-
completionHandler(error, image, nil, nil);
381+
completionHandler(error, image, nil);
382382
}];
383383
}
384384

@@ -402,25 +402,13 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
402402
progressHandler:progressHandler
403403
partialLoadHandler:partialLoadHandler
404404
completionHandler:^(NSError *error, UIImage *image) {
405-
completionHandler(error, image, nil, nil);
405+
completionHandler(error, image, nil);
406406
}];
407407
} else {
408-
UIImage *image;
409-
if (cacheResult) {
410-
image = [[strongSelf imageCache] imageForUrl:request.URL.absoluteString
411-
size:size
412-
scale:scale
413-
resizeMode:resizeMode];
414-
}
415-
416-
if (image) {
417-
completionHandler(nil, image, nil, nil);
418-
} else {
419-
// Use networking module to load image
420-
cancelLoad = [strongSelf _loadURLRequest:request
421-
progressBlock:progressHandler
422-
completionBlock:completionHandler];
423-
}
408+
// Use networking module to load image
409+
cancelLoad = [strongSelf _loadURLRequest:request
410+
progressBlock:progressHandler
411+
completionBlock:completionHandler];
424412
}
425413
});
426414

@@ -439,7 +427,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest
439427

440428
- (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request
441429
progressBlock:(RCTImageLoaderProgressBlock)progressHandler
442-
completionBlock:(void (^)(NSError *error, id imageOrData, NSString *fetchDate, NSString *cacheControl))completionHandler
430+
completionBlock:(void (^)(NSError *error, id imageOrData, NSString *fetchDate))completionHandler
443431
{
444432
// Check if networking module is available
445433
if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) {
@@ -461,36 +449,34 @@ - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request
461449
RCTURLRequestCompletionBlock processResponse = ^(NSURLResponse *response, NSData *data, NSError *error) {
462450
// Check for system errors
463451
if (error) {
464-
completionHandler(error, nil, nil, nil);
452+
completionHandler(error, nil, nil);
465453
return;
466454
} else if (!response) {
467-
completionHandler(RCTErrorWithMessage(@"Response metadata error"), nil, nil, nil);
455+
completionHandler(RCTErrorWithMessage(@"Response metadata error"), nil, nil);
468456
return;
469457
} else if (!data) {
470-
completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil, nil, nil);
458+
completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil, nil);
471459
return;
472460
}
473461

474462
// Check for http errors
475463
NSString *responseDate;
476-
NSString *cacheControl;
477464
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
478465
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
479466
if (statusCode != 200) {
480467
NSString *errorMessage = [NSString stringWithFormat:@"Failed to load %@", response.URL];
481468
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: errorMessage};
482469
completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
483470
code:statusCode
484-
userInfo:userInfo], nil, nil, nil);
471+
userInfo:userInfo], nil, nil);
485472
return;
486473
}
487474

488475
responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"];
489-
cacheControl = ((NSHTTPURLResponse *)response).allHeaderFields[@"Cache-Control"];
490476
}
491477

492478
// Call handler
493-
completionHandler(nil, data, responseDate, cacheControl);
479+
completionHandler(nil, data, responseDate);
494480
};
495481

496482
// Download image
@@ -512,7 +498,7 @@ - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request
512498
} else {
513499
someError = RCTErrorWithMessage(@"Unknown image download error");
514500
}
515-
completionHandler(someError, nil, nil, nil);
501+
completionHandler(someError, nil, nil);
516502
[strongSelf dequeueTasks];
517503
return;
518504
}
@@ -578,7 +564,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image
578564
};
579565

580566
__weak RCTImageLoader *weakSelf = self;
581-
void (^completionHandler)(NSError *, id, BOOL, NSString *, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate, NSString *cacheControl) {
567+
void (^completionHandler)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
582568
__typeof(self) strongSelf = weakSelf;
583569
if (atomic_load(&cancelled) || !strongSelf) {
584570
return;
@@ -590,6 +576,20 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image
590576
return;
591577
}
592578

579+
// Check decoded image cache
580+
if (cacheResult) {
581+
UIImage *image = [[strongSelf imageCache] imageForUrl:imageURLRequest.URL.absoluteString
582+
size:size
583+
scale:scale
584+
resizeMode:resizeMode
585+
responseDate:fetchDate];
586+
if (image) {
587+
cancelLoad = nil;
588+
completionBlock(nil, image);
589+
return;
590+
}
591+
}
592+
593593
RCTImageLoaderCompletionBlock decodeCompletionHandler = ^(NSError *error_, UIImage *image) {
594594
if (cacheResult && image) {
595595
// Store decoded image in cache
@@ -598,8 +598,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image
598598
size:size
599599
scale:scale
600600
resizeMode:resizeMode
601-
responseDate:fetchDate
602-
cacheControl:cacheControl];
601+
responseDate:fetchDate];
603602
}
604603

605604
cancelLoad = nil;
@@ -733,7 +732,7 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
733732
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
734733
block:(void(^)(NSError *error, CGSize size))callback
735734
{
736-
void (^completion)(NSError *, id, BOOL, NSString *, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate, NSString *cacheControl) {
735+
void (^completion)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) {
737736
CGSize size;
738737
if ([imageOrData isKindOfClass:[NSData class]]) {
739738
NSDictionary *meta = RCTGetImageMetadata(imageOrData);

0 commit comments

Comments
 (0)