From bbad1bcfcc7c1a419f5920bfa049a7700c077cb3 Mon Sep 17 00:00:00 2001 From: Steven Chan Date: Tue, 12 Mar 2013 01:08:57 +0800 Subject: [PATCH] New option SDWebImageRefreshCached Even if the image is cached, fetch the URL again anyway. When set, NSURLCache is enabled in the downloader via the new option SDWebImageDownloaderEnableNSURLCache. NSURLCache will handle the protocol caching while SDWebImage remains useful for offline images. This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics where the request URL https://graph.facebook.com/[userid]/picture returns a redirect to the actual profile image. If a cached image exists, the completion block is called once with the cached image and again with the final image. --- SDWebImage/SDWebImageDownloader.h | 3 ++- SDWebImage/SDWebImageDownloader.m | 2 +- SDWebImage/SDWebImageManager.h | 9 ++++++++- SDWebImage/SDWebImageManager.m | 15 ++++++++++----- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/SDWebImage/SDWebImageDownloader.h b/SDWebImage/SDWebImageDownloader.h index ffc929e..1fab7e4 100644 --- a/SDWebImage/SDWebImageDownloader.h +++ b/SDWebImage/SDWebImageDownloader.h @@ -13,7 +13,8 @@ typedef enum { SDWebImageDownloaderLowPriority = 1 << 0, - SDWebImageDownloaderProgressiveDownload = 1 << 1 + SDWebImageDownloaderProgressiveDownload = 1 << 1, + SDWebImageDownloaderEnableNSURLCache = 1 << 2 } SDWebImageDownloaderOptions; typedef enum diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 3401ee4..1dbe85a 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -120,7 +120,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; [self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^ { // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests - NSMutableURLRequest *request = [NSMutableURLRequest.alloc initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; + NSMutableURLRequest *request = [NSMutableURLRequest.alloc initWithURL:url cachePolicy:(options & SDWebImageDownloaderEnableNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:15]; request.HTTPShouldHandleCookies = NO; request.HTTPShouldUsePipelining = YES; request.allHTTPHeaderFields = wself.HTTPHeaders; diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 84316e1..a686978 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -31,7 +31,14 @@ typedef enum * This flag enables progressive download, the image is displayed progressively during download as a browser would do. * By default, the image is only displayed once completely downloaded. */ - SDWebImageProgressiveDownload = 1 << 3 + SDWebImageProgressiveDownload = 1 << 3, + /** + * Even if the image is cached, fetch the URL again anyway. When set, NSURLCache is enabled in the downloader. + * NSURLCache will handle the protocol caching logic while SDWebImage remains useful for offline images. + * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics. + * If a cached image exists, the completion block is called once with the cached image and again with the final image. + */ + SDWebImageRefreshCached = 1 << 4 } SDWebImageOptions; typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType); diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 7a44560..5dc965d 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -97,16 +97,21 @@ if (image) { completedBlock(image, nil, cacheType, YES); - @synchronized(self.runningOperations) - { - [self.runningOperations removeObject:operation]; + if (!(options & SDWebImageRefreshCached)) { + @synchronized(self.runningOperations) + { + [self.runningOperations removeObject:operation]; + } } } - else if (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]) + + if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) { + // download if no image or requested to refresh anyway, and download allowed by delegate SDWebImageDownloaderOptions downloaderOptions = 0; if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; + if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderEnableNSURLCache; __block id subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) { if (weakOperation.cancelled) @@ -167,7 +172,7 @@ }]; operation.cancelBlock = ^{[subOperation cancel];}; } - else + else if (!image) { // Image not in cache and download disallowed by delegate completedBlock(nil, nil, SDImageCacheTypeNone, YES);