Add `SDWebImageManager` delegate allowing fine control of manager's cache-in

- `imageManager:shouldDownloadImageForURL:` let delegate to conditionaly block cache-in (fix #134)
- `imageManager:transformDownloadedImage:` let delegate to transform the image prior to cache-in (fix #63, fix #284)
This commit is contained in:
Olivier Poitrey 2013-02-17 00:55:27 +01:00
parent 6f198abd1b
commit ebd63a88c1
2 changed files with 72 additions and 5 deletions

View File

@ -38,6 +38,36 @@ typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageC
typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished);
@class SDWebImageManager;
@protocol SDWebImageManagerDelegate <NSObject>
@optional
/**
* Controls which image should be downloaded when the image is not found in the cache.
*
* @param imageManager The current `SDWebImageManager`
* @param imageURL The url of the image to be downloaded
*
* @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied.
*/
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
/**
* Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
* NOTE: This method is called from a global queue in order to not to block the main thread.
*
* @param imageManager The current `SDWebImageManager`
* @param image The image to transform
* @param imageURL The url of the image to transform
*
* @return The transformed image object.
*/
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;
@end
/**
* The SDWebImageManager is the class behind the UIImageView+WebCache category and likes.
* It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache).
@ -61,6 +91,8 @@ typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *err
*/
@interface SDWebImageManager : NSObject
@property (weak, nonatomic) id<SDWebImageManagerDelegate> delegate;
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;

View File

@ -101,17 +101,17 @@
[self.runningOperations removeObject:operation];
}
}
else
else if (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])
{
SDWebImageDownloaderOptions downloaderOptions = 0;
if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
__block id<SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished)
{
completedBlock(downloadedImage, error, SDImageCacheTypeNone, finished);
if (error)
{
completedBlock(nil, error, SDImageCacheTypeNone, finished);
if (error.code != NSURLErrorNotConnectedToInternet)
{
@synchronized(self.failedURLs)
@ -120,10 +120,36 @@
}
}
}
else if (downloadedImage && finished)
else
{
const BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
[self.imageCache storeImage:downloadedImage imageData:data forKey:key toDisk:cacheOnDisk];
if (downloadedImage && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)])
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
{
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
dispatch_async(dispatch_get_main_queue(), ^
{
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished);
});
if (transformedImage && finished)
{
[self.imageCache storeImage:transformedImage imageData:data forKey:key toDisk:cacheOnDisk];
}
});
}
else
{
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
if (downloadedImage && finished)
{
[self.imageCache storeImage:downloadedImage imageData:data forKey:key toDisk:cacheOnDisk];
}
}
}
if (finished)
@ -136,6 +162,15 @@
}];
operation.cancelBlock = ^{[subOperation cancel];};
}
else
{
// Image not in cache and download disallowed by delegate
completedBlock(nil, nil, SDImageCacheTypeNone, YES);
@synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}
}
}];
return operation;