Perform disk cache out operations asynchronousely in order to prevent from blocking the main runloop when a lot of cache queries are performed at the same time
This commit is contained in:
parent
dffff12607
commit
2b352c3c3a
|
@ -7,12 +7,13 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SDImageCacheDelegate.h"
|
||||
|
||||
@interface SDImageCache : NSObject
|
||||
{
|
||||
NSMutableDictionary *memCache, *storeDataQueue;
|
||||
NSString *diskCachePath;
|
||||
NSOperationQueue *cacheInQueue;
|
||||
NSOperationQueue *cacheInQueue, *cacheOutQueue;
|
||||
}
|
||||
|
||||
+ (SDImageCache *)sharedImageCache;
|
||||
|
@ -21,6 +22,8 @@
|
|||
- (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)queryDiskCacheForKey:(NSString *)key delegate:(id <SDImageCacheDelegate>)delegate userInfo:(NSDictionary *)info;
|
||||
|
||||
- (void)removeImageForKey:(NSString *)key;
|
||||
- (void)clearMemory;
|
||||
- (void)clearDisk;
|
||||
|
|
|
@ -39,7 +39,9 @@ static SDImageCache *instance;
|
|||
|
||||
// Init the operation queue
|
||||
cacheInQueue = [[NSOperationQueue alloc] init];
|
||||
cacheInQueue.maxConcurrentOperationCount = 2;
|
||||
cacheInQueue.maxConcurrentOperationCount = 1;
|
||||
cacheOutQueue = [[NSOperationQueue alloc] init];
|
||||
cacheOutQueue.maxConcurrentOperationCount = 1;
|
||||
|
||||
// Subscribe to app events
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
|
@ -134,6 +136,45 @@ static SDImageCache *instance;
|
|||
[fileManager release];
|
||||
}
|
||||
|
||||
- (void)notifyDelegate:(NSDictionary *)arguments
|
||||
{
|
||||
NSString *key = [arguments objectForKey:@"key"];
|
||||
id <SDImageCacheDelegate> delegate = [arguments objectForKey:@"delegate"];
|
||||
NSDictionary *info = [arguments objectForKey:@"userInfo"];
|
||||
UIImage *image = [arguments objectForKey:@"image"];
|
||||
|
||||
if (image)
|
||||
{
|
||||
[memCache setObject:image forKey:key];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(imageCache:didFindImage:forKey:userInfo:)])
|
||||
{
|
||||
[delegate imageCache:self didFindImage:image forKey:key userInfo:info];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([delegate respondsToSelector:@selector(imageCache:didNotFindImageForKey:userInfo:)])
|
||||
{
|
||||
[delegate imageCache:self didNotFindImageForKey:key userInfo:info];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)queryDiskCacheOperation:(NSDictionary *)arguments
|
||||
{
|
||||
NSString *key = [arguments objectForKey:@"key"];
|
||||
NSMutableDictionary *mutableArguments = [[arguments mutableCopy] autorelease];
|
||||
|
||||
UIImage *image = [[[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]] autorelease];
|
||||
if (image)
|
||||
{
|
||||
[mutableArguments setObject:image forKey:@"image"];
|
||||
}
|
||||
|
||||
[self performSelectorOnMainThread:@selector(notifyDelegate:) withObject:mutableArguments waitUntilDone:NO];
|
||||
}
|
||||
|
||||
#pragma mark ImageCache
|
||||
|
||||
- (void)storeImage:(UIImage *)image imageData:(NSData *)data forKey:(NSString *)key toDisk:(BOOL)toDisk
|
||||
|
@ -154,7 +195,6 @@ static SDImageCache *instance;
|
|||
{
|
||||
[storeDataQueue setObject:data forKey:key];
|
||||
[cacheInQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(storeKeyToDisk:) object:key] autorelease]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,17 +225,54 @@ static SDImageCache *instance;
|
|||
|
||||
if (!image && fromDisk)
|
||||
{
|
||||
image = [[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]];
|
||||
if (image != nil)
|
||||
image = [[[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]] autorelease];
|
||||
if (image)
|
||||
{
|
||||
[memCache setObject:image forKey:key];
|
||||
[image autorelease];
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)queryDiskCacheForKey:(NSString *)key delegate:(id <SDImageCacheDelegate>)delegate userInfo:(NSDictionary *)info
|
||||
{
|
||||
if (!delegate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!key)
|
||||
{
|
||||
if ([delegate respondsToSelector:@selector(imageCache:didNotFindImageForKey:userInfo:)])
|
||||
{
|
||||
[delegate imageCache:self didNotFindImageForKey:key userInfo:info];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// First check the in-memory cache...
|
||||
UIImage *image = [memCache objectForKey:key];
|
||||
if (image)
|
||||
{
|
||||
// ...notify delegate immediately, no need to go async
|
||||
if ([delegate respondsToSelector:@selector(imageCache:didFindImage:forKey:userInfo:)])
|
||||
{
|
||||
[delegate imageCache:self didFindImage:image forKey:key userInfo:info];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary *arguments = [NSMutableDictionary dictionaryWithCapacity:3];
|
||||
[arguments setObject:key forKey:@"key"];
|
||||
[arguments setObject:delegate forKey:@"delegate"];
|
||||
if (info)
|
||||
{
|
||||
[arguments setObject:info forKey:@"userInfo"];
|
||||
}
|
||||
[cacheOutQueue addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(queryDiskCacheOperation:) object:arguments] autorelease]];
|
||||
}
|
||||
|
||||
- (void)removeImageForKey:(NSString *)key
|
||||
{
|
||||
if (key == nil)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// SDImageCacheDelegate.h
|
||||
// Dailymotion
|
||||
//
|
||||
// Created by Olivier Poitrey on 16/09/10.
|
||||
// Copyright 2010 Dailymotion. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class SDImageCache;
|
||||
|
||||
@protocol SDImageCacheDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
- (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forKey:(NSString *)key userInfo:(NSDictionary *)info;
|
||||
- (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info;
|
||||
|
||||
@end
|
|
@ -9,8 +9,9 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import "SDWebImageDownloaderDelegate.h"
|
||||
#import "SDWebImageManagerDelegate.h"
|
||||
#import "SDImageCacheDelegate.h"
|
||||
|
||||
@interface SDWebImageManager : NSObject <SDWebImageDownloaderDelegate>
|
||||
@interface SDWebImageManager : NSObject <SDWebImageDownloaderDelegate, SDImageCacheDelegate>
|
||||
{
|
||||
NSMutableArray *delegates;
|
||||
NSMutableArray *downloaders;
|
||||
|
|
|
@ -46,6 +46,9 @@ static SDWebImageManager *instance;
|
|||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
- (UIImage *)imageWithURL:(NSURL *)url
|
||||
{
|
||||
return [[SDImageCache sharedImageCache] imageFromKey:[url absoluteString]];
|
||||
|
@ -53,22 +56,14 @@ static SDWebImageManager *instance;
|
|||
|
||||
- (void)downloadWithURL:(NSURL *)url delegate:(id<SDWebImageManagerDelegate>)delegate
|
||||
{
|
||||
if (url == nil || [failedURLs containsObject:url])
|
||||
if (!url || !delegate || [failedURLs containsObject:url])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Share the same downloader for identical URLs so we don't download the same URL several times
|
||||
SDWebImageDownloader *downloader = [downloaderForURL objectForKey:url];
|
||||
|
||||
if (!downloader)
|
||||
{
|
||||
downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self];
|
||||
[downloaderForURL setObject:downloader forKey:url];
|
||||
}
|
||||
|
||||
[delegates addObject:delegate];
|
||||
[downloaders addObject:downloader];
|
||||
// Check the on-disk cache async so we don't block the main thread
|
||||
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:delegate, @"delegate", url, @"url", nil];
|
||||
[[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString] delegate:self userInfo:info];
|
||||
}
|
||||
|
||||
- (void)cancelForDelegate:(id<SDWebImageManagerDelegate>)delegate
|
||||
|
@ -95,6 +90,37 @@ static SDWebImageManager *instance;
|
|||
[downloader release];
|
||||
}
|
||||
|
||||
#pragma mark SDImageCacheDelegate
|
||||
|
||||
- (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forKey:(NSString *)key userInfo:(NSDictionary *)info
|
||||
{
|
||||
id<SDWebImageManagerDelegate> delegate = [info objectForKey:@"delegate"];
|
||||
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)])
|
||||
{
|
||||
[delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info
|
||||
{
|
||||
NSURL *url = [info objectForKey:@"url"];
|
||||
id<SDWebImageManagerDelegate> delegate = [info objectForKey:@"delegate"];
|
||||
|
||||
// Share the same downloader for identical URLs so we don't download the same URL several times
|
||||
SDWebImageDownloader *downloader = [downloaderForURL objectForKey:url];
|
||||
|
||||
if (!downloader)
|
||||
{
|
||||
downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self];
|
||||
[downloaderForURL setObject:downloader forKey:url];
|
||||
}
|
||||
|
||||
[delegates addObject:delegate];
|
||||
[downloaders addObject:downloader];
|
||||
}
|
||||
|
||||
#pragma mark SDWebImageDownloaderDelegate
|
||||
|
||||
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image
|
||||
{
|
||||
[downloader retain];
|
||||
|
|
|
@ -23,31 +23,11 @@
|
|||
// Remove in progress downloader from queue
|
||||
[manager cancelForDelegate:self];
|
||||
|
||||
UIImage *cachedImage = nil;
|
||||
self.image = placeholder;
|
||||
|
||||
if (url)
|
||||
{
|
||||
cachedImage = [manager imageWithURL:url];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.image = placeholder;
|
||||
}
|
||||
|
||||
if (cachedImage)
|
||||
{
|
||||
self.image = cachedImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (placeholder)
|
||||
{
|
||||
self.image = placeholder;
|
||||
}
|
||||
|
||||
if (url)
|
||||
{
|
||||
[manager downloadWithURL:url delegate:self];
|
||||
}
|
||||
[manager downloadWithURL:url delegate:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue