From d2dc4cbbac3b141f9f74cadab293696593dfa680 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 29 Aug 2010 02:56:47 +0200 Subject: [PATCH] Do not convert images to JPEG when stored to disk for caching This saves CPU and memory in all cases and alpha channel / image clearness if orignal format was PNG or GIF. --- SDImageCache.h | 3 +- SDImageCache.m | 55 +++++++++++++++++++++++++++------- SDWebImageDownloader.h | 1 + SDWebImageDownloader.m | 12 ++++---- SDWebImageDownloaderDelegate.h | 1 + SDWebImageManager.m | 5 +++- 6 files changed, 59 insertions(+), 18 deletions(-) diff --git a/SDImageCache.h b/SDImageCache.h index d8c2a63a..c533639c 100644 --- a/SDImageCache.h +++ b/SDImageCache.h @@ -10,7 +10,7 @@ @interface SDImageCache : NSObject { - NSMutableDictionary *memCache; + NSMutableDictionary *memCache, *storeDataQueue; NSString *diskCachePath; NSOperationQueue *cacheInQueue; } @@ -18,6 +18,7 @@ + (SDImageCache *)sharedImageCache; - (void)storeImage:(UIImage *)image forKey:(NSString *)key; - (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk; +- (void)storeImage:(UIImage *)image imageData:(NSData *)data forKey:(NSString *)key toDisk:(BOOL)toDisk; - (UIImage *)imageFromKey:(NSString *)key; - (UIImage *)imageFromKey:(NSString *)key fromDisk:(BOOL)fromDisk; - (void)removeImageForKey:(NSString *)key; diff --git a/SDImageCache.m b/SDImageCache.m index 666be4fe..035f2eb3 100644 --- a/SDImageCache.m +++ b/SDImageCache.m @@ -25,6 +25,7 @@ static SDImageCache *instance; memCache = [[NSMutableDictionary alloc] init]; // Init the disk cache + storeDataQueue = [[NSMutableDictionary alloc] init]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); diskCachePath = [[[paths objectAtIndex:0] stringByAppendingPathComponent:@"ImageCache"] retain]; @@ -72,6 +73,7 @@ static SDImageCache *instance; [memCache release], memCache = nil; [diskCachePath release], diskCachePath = nil; [cacheInQueue release], cacheInQueue = nil; + [storeDataQueue release], storeDataQueue = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -105,25 +107,43 @@ static SDImageCache *instance; - (void)storeKeyToDisk:(NSString *)key { - UIImage *image = [[self imageFromKey:key fromDisk:YES] retain]; // be thread safe with no lock + // Can't use defaultManager another thread + NSFileManager *fileManager = [[NSFileManager alloc] init]; - if (image != nil) + NSData *data = [storeDataQueue objectForKey:key]; + if (data) { - [[NSFileManager defaultManager] createFileAtPath:[self cachePathForKey:key] contents:UIImageJPEGRepresentation(image, (CGFloat)1.0) attributes:nil]; - [image release]; + [fileManager createFileAtPath:[self cachePathForKey:key] contents:data attributes:nil]; + @synchronized(storeDataQueue) + { + [storeDataQueue removeObjectForKey:key]; + } } + else + { + // If no data representation given, convert the UIImage in JPEG and store it + // This trick is more CPU/memory intensive and doesn't preserve alpha channel + UIImage *image = [[self imageFromKey:key fromDisk:YES] retain]; // be thread safe with no lock + if (image) + { + [fileManager createFileAtPath:[self cachePathForKey:key] contents:UIImageJPEGRepresentation(image, (CGFloat)1.0) attributes:nil]; + [image release]; + } + } + + [fileManager release]; } #pragma mark ImageCache -- (void)storeImage:(UIImage *)image forKey:(NSString *)key +- (void)storeImage:(UIImage *)image imageData:(NSData *)data forKey:(NSString *)key toDisk:(BOOL)toDisk { - [self storeImage:image forKey:key toDisk:YES]; -} + if (!image || !key) + { + return; + } -- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk -{ - if (image == nil || key == nil) + if (toDisk && !data) { return; } @@ -132,10 +152,23 @@ static SDImageCache *instance; if (toDisk) { + [storeDataQueue setObject:data forKey:key]; [cacheInQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(storeKeyToDisk:) object:key] autorelease]]; + } } +- (void)storeImage:(UIImage *)image forKey:(NSString *)key +{ + [self storeImage:image imageData:nil forKey:key toDisk:YES]; +} + +- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk +{ + [self storeImage:image imageData:nil forKey:key toDisk:toDisk]; +} + + - (UIImage *)imageFromKey:(NSString *)key { return [self imageFromKey:key fromDisk:YES]; @@ -152,7 +185,7 @@ static SDImageCache *instance; if (!image && fromDisk) { - image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:[self cachePathForKey:key]]]; + image = [[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]]; if (image != nil) { [memCache setObject:image forKey:key]; diff --git a/SDWebImageDownloader.h b/SDWebImageDownloader.h index ddf258c8..7e12add9 100644 --- a/SDWebImageDownloader.h +++ b/SDWebImageDownloader.h @@ -20,6 +20,7 @@ @property (nonatomic, retain) NSURL *url; @property (nonatomic, assign) id delegate; +@property (nonatomic, retain) NSMutableData *imageData; + (id)downloaderWithURL:(NSURL *)url delegate:(id)delegate; - (void)start; diff --git a/SDWebImageDownloader.m b/SDWebImageDownloader.m index 230f5626..1c8e918b 100644 --- a/SDWebImageDownloader.m +++ b/SDWebImageDownloader.m @@ -10,7 +10,6 @@ @interface SDWebImageDownloader () @property (nonatomic, retain) NSURLConnection *connection; -@property (nonatomic, retain) NSMutableData *imageData; @end @implementation SDWebImageDownloader @@ -73,16 +72,19 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)aConnection { - UIImage *image = [[UIImage alloc] initWithData:imageData]; - self.imageData = nil; self.connection = nil; + if ([delegate respondsToSelector:@selector(imageDownloaderDidFinish:)]) + { + [delegate performSelector:@selector(imageDownloaderDidFinish:) withObject:self]; + } + if ([delegate respondsToSelector:@selector(imageDownloader:didFinishWithImage:)]) { + UIImage *image = [[UIImage alloc] initWithData:imageData]; [delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image]; + [image release]; } - - [image release]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error diff --git a/SDWebImageDownloaderDelegate.h b/SDWebImageDownloaderDelegate.h index 82d07d22..08939be9 100644 --- a/SDWebImageDownloaderDelegate.h +++ b/SDWebImageDownloaderDelegate.h @@ -12,6 +12,7 @@ @optional +- (void)imageDownloaderDidFinish:(SDWebImageDownloader *)downloader; - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image; - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error; diff --git a/SDWebImageManager.m b/SDWebImageManager.m index 8f97809d..7c02b18a 100644 --- a/SDWebImageManager.m +++ b/SDWebImageManager.m @@ -120,7 +120,10 @@ static SDWebImageManager *instance; if (image) { // Store the image in the cache - [[SDImageCache sharedImageCache] storeImage:image forKey:[downloader.url absoluteString]]; + [[SDImageCache sharedImageCache] storeImage:image + imageData:downloader.imageData + forKey:[downloader.url absoluteString] + toDisk:YES]; } else {