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.
This commit is contained in:
parent
7f7dfbecd6
commit
d2dc4cbbac
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
@interface SDImageCache : NSObject
|
@interface SDImageCache : NSObject
|
||||||
{
|
{
|
||||||
NSMutableDictionary *memCache;
|
NSMutableDictionary *memCache, *storeDataQueue;
|
||||||
NSString *diskCachePath;
|
NSString *diskCachePath;
|
||||||
NSOperationQueue *cacheInQueue;
|
NSOperationQueue *cacheInQueue;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
+ (SDImageCache *)sharedImageCache;
|
+ (SDImageCache *)sharedImageCache;
|
||||||
- (void)storeImage:(UIImage *)image forKey:(NSString *)key;
|
- (void)storeImage:(UIImage *)image forKey:(NSString *)key;
|
||||||
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk;
|
- (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;
|
||||||
- (UIImage *)imageFromKey:(NSString *)key fromDisk:(BOOL)fromDisk;
|
- (UIImage *)imageFromKey:(NSString *)key fromDisk:(BOOL)fromDisk;
|
||||||
- (void)removeImageForKey:(NSString *)key;
|
- (void)removeImageForKey:(NSString *)key;
|
||||||
|
|
|
@ -25,6 +25,7 @@ static SDImageCache *instance;
|
||||||
memCache = [[NSMutableDictionary alloc] init];
|
memCache = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
// Init the disk cache
|
// Init the disk cache
|
||||||
|
storeDataQueue = [[NSMutableDictionary alloc] init];
|
||||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
diskCachePath = [[[paths objectAtIndex:0] stringByAppendingPathComponent:@"ImageCache"] retain];
|
diskCachePath = [[[paths objectAtIndex:0] stringByAppendingPathComponent:@"ImageCache"] retain];
|
||||||
|
|
||||||
|
@ -72,6 +73,7 @@ static SDImageCache *instance;
|
||||||
[memCache release], memCache = nil;
|
[memCache release], memCache = nil;
|
||||||
[diskCachePath release], diskCachePath = nil;
|
[diskCachePath release], diskCachePath = nil;
|
||||||
[cacheInQueue release], cacheInQueue = nil;
|
[cacheInQueue release], cacheInQueue = nil;
|
||||||
|
[storeDataQueue release], storeDataQueue = nil;
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
|
||||||
|
@ -105,25 +107,43 @@ static SDImageCache *instance;
|
||||||
|
|
||||||
- (void)storeKeyToDisk:(NSString *)key
|
- (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];
|
[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];
|
[image release];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[fileManager release];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark ImageCache
|
#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 (toDisk && !data)
|
||||||
{
|
|
||||||
if (image == nil || key == nil)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -132,10 +152,23 @@ static SDImageCache *instance;
|
||||||
|
|
||||||
if (toDisk)
|
if (toDisk)
|
||||||
{
|
{
|
||||||
|
[storeDataQueue setObject:data forKey:key];
|
||||||
[cacheInQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(storeKeyToDisk:) object:key] autorelease]];
|
[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
|
- (UIImage *)imageFromKey:(NSString *)key
|
||||||
{
|
{
|
||||||
return [self imageFromKey:key fromDisk:YES];
|
return [self imageFromKey:key fromDisk:YES];
|
||||||
|
@ -152,7 +185,7 @@ static SDImageCache *instance;
|
||||||
|
|
||||||
if (!image && fromDisk)
|
if (!image && fromDisk)
|
||||||
{
|
{
|
||||||
image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:[self cachePathForKey:key]]];
|
image = [[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]];
|
||||||
if (image != nil)
|
if (image != nil)
|
||||||
{
|
{
|
||||||
[memCache setObject:image forKey:key];
|
[memCache setObject:image forKey:key];
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
@property (nonatomic, retain) NSURL *url;
|
@property (nonatomic, retain) NSURL *url;
|
||||||
@property (nonatomic, assign) id<SDWebImageDownloaderDelegate> delegate;
|
@property (nonatomic, assign) id<SDWebImageDownloaderDelegate> delegate;
|
||||||
|
@property (nonatomic, retain) NSMutableData *imageData;
|
||||||
|
|
||||||
+ (id)downloaderWithURL:(NSURL *)url delegate:(id<SDWebImageDownloaderDelegate>)delegate;
|
+ (id)downloaderWithURL:(NSURL *)url delegate:(id<SDWebImageDownloaderDelegate>)delegate;
|
||||||
- (void)start;
|
- (void)start;
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
@interface SDWebImageDownloader ()
|
@interface SDWebImageDownloader ()
|
||||||
@property (nonatomic, retain) NSURLConnection *connection;
|
@property (nonatomic, retain) NSURLConnection *connection;
|
||||||
@property (nonatomic, retain) NSMutableData *imageData;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation SDWebImageDownloader
|
@implementation SDWebImageDownloader
|
||||||
|
@ -73,16 +72,19 @@
|
||||||
|
|
||||||
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
|
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
|
||||||
{
|
{
|
||||||
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
|
||||||
self.imageData = nil;
|
|
||||||
self.connection = nil;
|
self.connection = nil;
|
||||||
|
|
||||||
|
if ([delegate respondsToSelector:@selector(imageDownloaderDidFinish:)])
|
||||||
|
{
|
||||||
|
[delegate performSelector:@selector(imageDownloaderDidFinish:) withObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
if ([delegate respondsToSelector:@selector(imageDownloader:didFinishWithImage:)])
|
if ([delegate respondsToSelector:@selector(imageDownloader:didFinishWithImage:)])
|
||||||
{
|
{
|
||||||
|
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
||||||
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
|
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
|
||||||
}
|
|
||||||
|
|
||||||
[image release];
|
[image release];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
|
- (void)imageDownloaderDidFinish:(SDWebImageDownloader *)downloader;
|
||||||
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image;
|
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image;
|
||||||
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error;
|
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error;
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,10 @@ static SDWebImageManager *instance;
|
||||||
if (image)
|
if (image)
|
||||||
{
|
{
|
||||||
// Store the image in the cache
|
// 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
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue