diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 2afd6e1..84316e1 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -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 + +@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 delegate; + @property (strong, nonatomic, readonly) SDImageCache *imageCache; @property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader; diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index d69bc94..10bf52a 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -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 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;