Skip to content

Commit d2dc4cb

Browse files
author
Olivier Poitrey
committed
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.
1 parent 7f7dfbe commit d2dc4cb

File tree

6 files changed

+59
-18
lines changed

6 files changed

+59
-18
lines changed

SDImageCache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010

1111
@interface SDImageCache : NSObject
1212
{
13-
NSMutableDictionary *memCache;
13+
NSMutableDictionary *memCache, *storeDataQueue;
1414
NSString *diskCachePath;
1515
NSOperationQueue *cacheInQueue;
1616
}
1717

1818
+ (SDImageCache *)sharedImageCache;
1919
- (void)storeImage:(UIImage *)image forKey:(NSString *)key;
2020
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk;
21+
- (void)storeImage:(UIImage *)image imageData:(NSData *)data forKey:(NSString *)key toDisk:(BOOL)toDisk;
2122
- (UIImage *)imageFromKey:(NSString *)key;
2223
- (UIImage *)imageFromKey:(NSString *)key fromDisk:(BOOL)fromDisk;
2324
- (void)removeImageForKey:(NSString *)key;

SDImageCache.m

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ - (id)init
2525
memCache = [[NSMutableDictionary alloc] init];
2626

2727
// Init the disk cache
28+
storeDataQueue = [[NSMutableDictionary alloc] init];
2829
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
2930
diskCachePath = [[[paths objectAtIndex:0] stringByAppendingPathComponent:@"ImageCache"] retain];
3031

@@ -72,6 +73,7 @@ - (void)dealloc
7273
[memCache release], memCache = nil;
7374
[diskCachePath release], diskCachePath = nil;
7475
[cacheInQueue release], cacheInQueue = nil;
76+
[storeDataQueue release], storeDataQueue = nil;
7577

7678
[[NSNotificationCenter defaultCenter] removeObserver:self];
7779

@@ -105,25 +107,43 @@ - (NSString *)cachePathForKey:(NSString *)key
105107

106108
- (void)storeKeyToDisk:(NSString *)key
107109
{
108-
UIImage *image = [[self imageFromKey:key fromDisk:YES] retain]; // be thread safe with no lock
110+
// Can't use defaultManager another thread
111+
NSFileManager *fileManager = [[NSFileManager alloc] init];
109112

110-
if (image != nil)
113+
NSData *data = [storeDataQueue objectForKey:key];
114+
if (data)
111115
{
112-
[[NSFileManager defaultManager] createFileAtPath:[self cachePathForKey:key] contents:UIImageJPEGRepresentation(image, (CGFloat)1.0) attributes:nil];
113-
[image release];
116+
[fileManager createFileAtPath:[self cachePathForKey:key] contents:data attributes:nil];
117+
@synchronized(storeDataQueue)
118+
{
119+
[storeDataQueue removeObjectForKey:key];
120+
}
121+
}
122+
else
123+
{
124+
// If no data representation given, convert the UIImage in JPEG and store it
125+
// This trick is more CPU/memory intensive and doesn't preserve alpha channel
126+
UIImage *image = [[self imageFromKey:key fromDisk:YES] retain]; // be thread safe with no lock
127+
if (image)
128+
{
129+
[fileManager createFileAtPath:[self cachePathForKey:key] contents:UIImageJPEGRepresentation(image, (CGFloat)1.0) attributes:nil];
130+
[image release];
131+
}
114132
}
133+
134+
[fileManager release];
115135
}
116136

117137
#pragma mark ImageCache
118138

119-
- (void)storeImage:(UIImage *)image forKey:(NSString *)key
139+
- (void)storeImage:(UIImage *)image imageData:(NSData *)data forKey:(NSString *)key toDisk:(BOOL)toDisk
120140
{
121-
[self storeImage:image forKey:key toDisk:YES];
122-
}
141+
if (!image || !key)
142+
{
143+
return;
144+
}
123145

124-
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk
125-
{
126-
if (image == nil || key == nil)
146+
if (toDisk && !data)
127147
{
128148
return;
129149
}
@@ -132,10 +152,23 @@ - (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk
132152

133153
if (toDisk)
134154
{
155+
[storeDataQueue setObject:data forKey:key];
135156
[cacheInQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(storeKeyToDisk:) object:key] autorelease]];
157+
136158
}
137159
}
138160

161+
- (void)storeImage:(UIImage *)image forKey:(NSString *)key
162+
{
163+
[self storeImage:image imageData:nil forKey:key toDisk:YES];
164+
}
165+
166+
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk
167+
{
168+
[self storeImage:image imageData:nil forKey:key toDisk:toDisk];
169+
}
170+
171+
139172
- (UIImage *)imageFromKey:(NSString *)key
140173
{
141174
return [self imageFromKey:key fromDisk:YES];
@@ -152,7 +185,7 @@ - (UIImage *)imageFromKey:(NSString *)key fromDisk:(BOOL)fromDisk
152185

153186
if (!image && fromDisk)
154187
{
155-
image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:[self cachePathForKey:key]]];
188+
image = [[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]];
156189
if (image != nil)
157190
{
158191
[memCache setObject:image forKey:key];

SDWebImageDownloader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
@property (nonatomic, retain) NSURL *url;
2222
@property (nonatomic, assign) id<SDWebImageDownloaderDelegate> delegate;
23+
@property (nonatomic, retain) NSMutableData *imageData;
2324

2425
+ (id)downloaderWithURL:(NSURL *)url delegate:(id<SDWebImageDownloaderDelegate>)delegate;
2526
- (void)start;

SDWebImageDownloader.m

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
@interface SDWebImageDownloader ()
1212
@property (nonatomic, retain) NSURLConnection *connection;
13-
@property (nonatomic, retain) NSMutableData *imageData;
1413
@end
1514

1615
@implementation SDWebImageDownloader
@@ -73,16 +72,19 @@ - (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data
7372

7473
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
7574
{
76-
UIImage *image = [[UIImage alloc] initWithData:imageData];
77-
self.imageData = nil;
7875
self.connection = nil;
7976

77+
if ([delegate respondsToSelector:@selector(imageDownloaderDidFinish:)])
78+
{
79+
[delegate performSelector:@selector(imageDownloaderDidFinish:) withObject:self];
80+
}
81+
8082
if ([delegate respondsToSelector:@selector(imageDownloader:didFinishWithImage:)])
8183
{
84+
UIImage *image = [[UIImage alloc] initWithData:imageData];
8285
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
86+
[image release];
8387
}
84-
85-
[image release];
8688
}
8789

8890
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

SDWebImageDownloaderDelegate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
@optional
1414

15+
- (void)imageDownloaderDidFinish:(SDWebImageDownloader *)downloader;
1516
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image;
1617
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error;
1718

SDWebImageManager.m

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U
120120
if (image)
121121
{
122122
// Store the image in the cache
123-
[[SDImageCache sharedImageCache] storeImage:image forKey:[downloader.url absoluteString]];
123+
[[SDImageCache sharedImageCache] storeImage:image
124+
imageData:downloader.imageData
125+
forKey:[downloader.url absoluteString]
126+
toDisk:YES];
124127
}
125128
else
126129
{

0 commit comments

Comments
 (0)