From 402e5568f7f0311d636a31b185bd45208a950aec Mon Sep 17 00:00:00 2001 From: Dima Vartanian Date: Fri, 4 Jul 2014 17:00:04 -0400 Subject: [PATCH 1/2] Add a weak NSMapTable-based memory cache. This allows the cache to reference previously cached object that are still alive and reuse them instead of redownloading them or pulling them out of the disk cache. This is faster and uses less memory. --- SDWebImage/SDImageCache.m | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 396db09a3..4ba8ecb8a 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -32,6 +32,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { @interface SDImageCache () @property (strong, nonatomic) NSCache *memCache; +@property (strong, nonatomic) NSMapTable *weakMemCache; @property (strong, nonatomic) NSString *diskCachePath; @property (strong, nonatomic) NSMutableArray *customPaths; @property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t ioQueue; @@ -70,6 +71,9 @@ - (id)initWithNamespace:(NSString *)ns { // Init the memory cache _memCache = [[NSCache alloc] init]; _memCache.name = fullNamespace; + + // Init the weak memory cache (to keep a weak reference to images cleared from our memory cache that are actually still alive) + _weakMemCache = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory]; // Init the disk cache NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); @@ -146,8 +150,7 @@ - (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate image if (!image || !key) { return; } - - [self.memCache setObject:image forKey:key cost:image.size.height * image.size.width * image.scale]; + [self addImageToMemoryCache:image forKey:key]; if (toDisk) { dispatch_async(self.ioQueue, ^{ @@ -209,7 +212,21 @@ - (BOOL)diskImageExistsWithKey:(NSString *)key { } - (UIImage *)imageFromMemoryCacheForKey:(NSString *)key { - return [self.memCache objectForKey:key]; + UIImage *image = [self.memCache objectForKey:key]; + // Check the weak memory cache to see if a previously cached image is still alive + if (!image) { + image = [self.weakMemCache objectForKey:key]; + if (image) { + // re-add to memory cache + [self addImageToMemoryCache:image forKey:key]; + } + } + return image; +} + +- (void) addImageToMemoryCache:(UIImage *)image forKey:(NSString *)key { + [self.memCache setObject:image forKey:key cost:image.size.height * image.size.width * image.scale]; + [self.weakMemCache setObject:image forKey:key]; } - (UIImage *)imageFromDiskCacheForKey:(NSString *)key { @@ -218,12 +235,11 @@ - (UIImage *)imageFromDiskCacheForKey:(NSString *)key { if (image) { return image; } - + // Second check the disk cache... UIImage *diskImage = [self diskImageForKey:key]; if (diskImage) { - CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale; - [self.memCache setObject:diskImage forKey:key cost:cost]; + [self addImageToMemoryCache:diskImage forKey:key]; } return diskImage; @@ -290,8 +306,7 @@ - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *im @autoreleasepool { UIImage *diskImage = [self diskImageForKey:key]; if (diskImage) { - CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale; - [self.memCache setObject:diskImage forKey:key cost:cost]; + [self addImageToMemoryCache:diskImage forKey:key]; } dispatch_async(dispatch_get_main_queue(), ^{ From f9dda4264b4bc0714aa88373a9d1b97ab67a08a4 Mon Sep 17 00:00:00 2001 From: Dima Vartanian Date: Sat, 5 Jul 2014 15:15:00 -0400 Subject: [PATCH 2/2] user more concise initializer --- SDWebImage/SDImageCache.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 4ba8ecb8a..b4f411614 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -73,7 +73,7 @@ - (id)initWithNamespace:(NSString *)ns { _memCache.name = fullNamespace; // Init the weak memory cache (to keep a weak reference to images cleared from our memory cache that are actually still alive) - _weakMemCache = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory]; + _weakMemCache = [NSMapTable strongToWeakObjectsMapTable]; // Init the disk cache NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);