From dcac94ebc904b451ae75fb67271364eb8e956e2e Mon Sep 17 00:00:00 2001 From: Michal Zelinka Date: Wed, 14 Aug 2013 11:40:52 +0200 Subject: [PATCH 01/13] Fix for infinite recursion issue caused by missing call parameter of failureBlock --- UIImageView+JMImageCache.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index 3a3502a..a0053ae 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -53,7 +53,7 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) [self setImageWithURL:url key:key placeholder:placeholderImage completionBlock:nil]; } - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *)placeholderImage completionBlock:(void (^)(UIImage *image))completionBlock { - [self setImageWithURL:url key:key placeholder:placeholderImage completionBlock:completionBlock]; + [self setImageWithURL:url key:key placeholder:placeholderImage completionBlock:completionBlock failureBlock:nil]; } - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *)placeholderImage completionBlock:(void (^)(UIImage *image))completionBlock failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failureBlock{ self.jm_imageURL = url; From 3ffcea3a41118a4f1bda995382cda9a366ba41f3 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 14:00:58 +0100 Subject: [PATCH 02/13] minor refactor & support for IOS4.3. --- UIImageView+JMImageCache.m | 43 ++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index a0053ae..b5978a7 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -55,55 +55,45 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *)placeholderImage completionBlock:(void (^)(UIImage *image))completionBlock { [self setImageWithURL:url key:key placeholder:placeholderImage completionBlock:completionBlock failureBlock:nil]; } + - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *)placeholderImage completionBlock:(void (^)(UIImage *image))completionBlock failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failureBlock{ self.jm_imageURL = url; - self.image = placeholderImage; - - [self setNeedsDisplay]; - [self setNeedsLayout]; - - __weak UIImageView *safeSelf = self; + [self assignImage:placeholderImage refreshSafeSelf:self]; + + __unsafe_unretained UIImageView *safeSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - UIImage *i; + UIImage *cachedImage; if (key) { - i = [[JMImageCache sharedCache] cachedImageForKey:key]; + cachedImage = [[JMImageCache sharedCache] cachedImageForKey:key]; } else { - i = [[JMImageCache sharedCache] cachedImageForURL:url]; + cachedImage = [[JMImageCache sharedCache] cachedImageForURL:url]; } - if(i) { + if(cachedImage) { dispatch_async(dispatch_get_main_queue(), ^{ safeSelf.jm_imageURL = nil; - safeSelf.image = i; - - [safeSelf setNeedsLayout]; - [safeSelf setNeedsDisplay]; + [self assignImage:cachedImage refreshSafeSelf:safeSelf]; }); } else { dispatch_async(dispatch_get_main_queue(), ^{ - safeSelf.image = placeholderImage; - - [safeSelf setNeedsDisplay]; - [safeSelf setNeedsLayout]; + [self assignImage:placeholderImage refreshSafeSelf:safeSelf]; }); [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { if ([url isEqual:safeSelf.jm_imageURL]) { dispatch_async(dispatch_get_main_queue(), ^{ if(image) { - safeSelf.image = image; + [self assignImage:image refreshSafeSelf:safeSelf]; + } else { - safeSelf.image = placeholderImage; + [self assignImage:placeholderImage refreshSafeSelf:safeSelf]; } safeSelf.jm_imageURL = nil; - [safeSelf setNeedsLayout]; - [safeSelf setNeedsDisplay]; - if (completionBlock) completionBlock(image); }); } @@ -116,4 +106,11 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) }); } +- (void)assignImage:(UIImage *)cachedImage refreshSafeSelf:(__unsafe_unretained UIImageView *)safeSelf { + safeSelf.image = cachedImage; + + [safeSelf setNeedsLayout]; + [safeSelf setNeedsDisplay]; +} + @end \ No newline at end of file From eaf552145cdbf4d0676bb8b26d94688983b0cf96 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 14:29:24 +0100 Subject: [PATCH 03/13] quick refactor --- UIImageView+JMImageCache.m | 83 +++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index b5978a7..892d3f3 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -61,52 +61,61 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) [self assignImage:placeholderImage refreshSafeSelf:self]; __unsafe_unretained UIImageView *safeSelf = self; - + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - UIImage *cachedImage; + + UIImage *cachedImage = [self getImageFromSharedCacheWith:url key:key]; - if (key) { - cachedImage = [[JMImageCache sharedCache] cachedImageForKey:key]; - } else { - cachedImage = [[JMImageCache sharedCache] cachedImageForURL:url]; + if (cachedImage) { + [self assignImage:cachedImage onMainQueueWithSafeSelf:safeSelf]; + return ; } - - if(cachedImage) { - dispatch_async(dispatch_get_main_queue(), ^{ - safeSelf.jm_imageURL = nil; - - [self assignImage:cachedImage refreshSafeSelf:safeSelf]; - }); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - [self assignImage:placeholderImage refreshSafeSelf:safeSelf]; - }); - - [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { - if ([url isEqual:safeSelf.jm_imageURL]) { - dispatch_async(dispatch_get_main_queue(), ^{ - if(image) { - [self assignImage:image refreshSafeSelf:safeSelf]; - - } else { - [self assignImage:placeholderImage refreshSafeSelf:safeSelf]; - } - - safeSelf.jm_imageURL = nil; - - if (completionBlock) completionBlock(image); - }); + + [self assignImage:placeholderImage onMainQueueWithSafeSelf:safeSelf]; + + [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { + if ([url isEqual:safeSelf.jm_imageURL]) { + + if (image) { + [self assignImage:image onMainQueueWithSafeSelf:safeSelf]; + } else { + [self assignImage:placeholderImage onMainQueueWithSafeSelf:safeSelf]; } + dispatch_async(dispatch_get_main_queue(), ^{ + + safeSelf.jm_imageURL = nil; + + if (completionBlock) completionBlock(image); + }); } - failureBlock:^(NSURLRequest *request, NSURLResponse *response, NSError* error) - { - if (failureBlock) failureBlock(request, response, error); - }]; } + failureBlock:^(NSURLRequest *request, NSURLResponse *response, NSError* error) + { + if (failureBlock) failureBlock(request, response, error); + }]; + }); } -- (void)assignImage:(UIImage *)cachedImage refreshSafeSelf:(__unsafe_unretained UIImageView *)safeSelf { +- (void)assignImage:(UIImage *)cachedImage onMainQueueWithSafeSelf:(__unsafe_unretained UIImageView *)safeSelf{ + dispatch_async(dispatch_get_main_queue(), ^{ + safeSelf.jm_imageURL = nil; + + [self assignImage:cachedImage refreshSafeSelf:safeSelf]; + }); +} + +- (UIImage *)getImageFromSharedCacheWith:(NSURL *)url key:(NSString *)key { + UIImage *cachedImage; + if (key) { + cachedImage = [[JMImageCache sharedCache] cachedImageForKey:key]; + } else { + cachedImage = [[JMImageCache sharedCache] cachedImageForURL:url]; + } + return cachedImage; +} + +- (void) assignImage:(UIImage *)cachedImage refreshSafeSelf:(__unsafe_unretained UIImageView *)safeSelf { safeSelf.image = cachedImage; [safeSelf setNeedsLayout]; From bf22e97bcaa451be1b0d15d61974fba1ffbca085 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 14:33:17 +0100 Subject: [PATCH 04/13] removed duplicated code logic --- JMImageCache.m | 4 ++++ UIImageView+JMImageCache.m | 12 +----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/JMImageCache.m b/JMImageCache.m index 007958e..53a8d3a 100644 --- a/JMImageCache.m +++ b/JMImageCache.m @@ -162,6 +162,10 @@ - (void) imageForURL:(NSURL *)url key:(NSString *)key completionBlock:(void (^)( UIImage *i = [self cachedImageForKey:key]; + if (!i) { + i = [self cachedImageForURL:url]; + } + if(i) { if(completion) completion(i); } else { diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index 892d3f3..9e9fd48 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -63,17 +63,7 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) __unsafe_unretained UIImageView *safeSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - - UIImage *cachedImage = [self getImageFromSharedCacheWith:url key:key]; - - if (cachedImage) { - [self assignImage:cachedImage onMainQueueWithSafeSelf:safeSelf]; - return ; - } - - [self assignImage:placeholderImage onMainQueueWithSafeSelf:safeSelf]; - - [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { + [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { if ([url isEqual:safeSelf.jm_imageURL]) { if (image) { From 1cb2d586b9a70ae6a93cf0f81aa1b6567ffe47d2 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 14:35:24 +0100 Subject: [PATCH 05/13] formatting --- UIImageView+JMImageCache.m | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index 9e9fd48..45767f2 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -63,11 +63,11 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) __unsafe_unretained UIImageView *safeSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { + [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { if ([url isEqual:safeSelf.jm_imageURL]) { - + if (image) { - [self assignImage:image onMainQueueWithSafeSelf:safeSelf]; + [self assignImage:image onMainQueueWithSafeSelf:safeSelf]; } else { [self assignImage:placeholderImage onMainQueueWithSafeSelf:safeSelf]; } @@ -89,8 +89,6 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) - (void)assignImage:(UIImage *)cachedImage onMainQueueWithSafeSelf:(__unsafe_unretained UIImageView *)safeSelf{ dispatch_async(dispatch_get_main_queue(), ^{ - safeSelf.jm_imageURL = nil; - [self assignImage:cachedImage refreshSafeSelf:safeSelf]; }); } @@ -98,10 +96,10 @@ - (void)assignImage:(UIImage *)cachedImage onMainQueueWithSafeSelf:(__unsafe_unr - (UIImage *)getImageFromSharedCacheWith:(NSURL *)url key:(NSString *)key { UIImage *cachedImage; if (key) { - cachedImage = [[JMImageCache sharedCache] cachedImageForKey:key]; - } else { - cachedImage = [[JMImageCache sharedCache] cachedImageForURL:url]; - } + cachedImage = [[JMImageCache sharedCache] cachedImageForKey:key]; + } else { + cachedImage = [[JMImageCache sharedCache] cachedImageForURL:url]; + } return cachedImage; } From 2f0c34dd257f72a3752faac450fe4f6b3ccdc613 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 16:28:38 +0100 Subject: [PATCH 06/13] cleanup --- UIImageView+JMImageCache.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index 45767f2..c4ab775 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -58,7 +58,7 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *)placeholderImage completionBlock:(void (^)(UIImage *image))completionBlock failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failureBlock{ self.jm_imageURL = url; - [self assignImage:placeholderImage refreshSafeSelf:self]; + [self assignImage:placeholderImage]; __unsafe_unretained UIImageView *safeSelf = self; @@ -67,9 +67,9 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) if ([url isEqual:safeSelf.jm_imageURL]) { if (image) { - [self assignImage:image onMainQueueWithSafeSelf:safeSelf]; + [safeSelf assignImageOnMainQueue:image]; } else { - [self assignImage:placeholderImage onMainQueueWithSafeSelf:safeSelf]; + [safeSelf assignImageOnMainQueue:placeholderImage]; } dispatch_async(dispatch_get_main_queue(), ^{ @@ -87,9 +87,9 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) }); } -- (void)assignImage:(UIImage *)cachedImage onMainQueueWithSafeSelf:(__unsafe_unretained UIImageView *)safeSelf{ +- (void)assignImageOnMainQueue:(UIImage *)cachedImage { dispatch_async(dispatch_get_main_queue(), ^{ - [self assignImage:cachedImage refreshSafeSelf:safeSelf]; + [self assignImage:cachedImage]; }); } @@ -103,11 +103,11 @@ - (UIImage *)getImageFromSharedCacheWith:(NSURL *)url key:(NSString *)key { return cachedImage; } -- (void) assignImage:(UIImage *)cachedImage refreshSafeSelf:(__unsafe_unretained UIImageView *)safeSelf { - safeSelf.image = cachedImage; +- (void)assignImage:(UIImage *)cachedImage { + self.image = cachedImage; - [safeSelf setNeedsLayout]; - [safeSelf setNeedsDisplay]; + [self setNeedsLayout]; + [self setNeedsDisplay]; } @end \ No newline at end of file From 3a549ee4aeb1ff0827bc5b81b637075d705241ac Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 17:02:12 +0100 Subject: [PATCH 07/13] checking on http status code 304 --- JMImageCache.m | 121 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 37 deletions(-) diff --git a/JMImageCache.m b/JMImageCache.m index 53a8d3a..c43bf9c 100644 --- a/JMImageCache.m +++ b/JMImageCache.m @@ -15,7 +15,7 @@ dispatch_once(&onceToken, ^{ _JMImageCacheDirectory = [[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/JMCache"] copy]; }); - + return _JMImageCacheDirectory; } inline static NSString *keyForURL(NSURL *url) { @@ -41,20 +41,20 @@ @implementation JMImageCache + (JMImageCache *) sharedCache { static JMImageCache *_sharedCache = nil; static dispatch_once_t onceToken; - + dispatch_once(&onceToken, ^{ _sharedCache = [[JMImageCache alloc] init]; }); - + return _sharedCache; } - (id) init { self = [super init]; if(!self) return nil; - + self.diskOperationQueue = [[NSOperationQueue alloc] init]; - + [[NSFileManager defaultManager] createDirectoryAtPath:JMImageCacheDirectory() withIntermediateDirectories:YES attributes:nil @@ -65,14 +65,24 @@ - (id) init { - (void) _downloadAndWriteImageForURL:(NSURL *)url key:(NSString *)key completionBlock:(void (^)(UIImage *image))completion failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failure { if (!key && !url) return; - + if (!key) { key = keyForURL(url); } - + + __unsafe_unretained JMImageCache *safeSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSURLRequest* request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [NSURLRequest requestWithURL:url]; + + NSDate *lastUpdated = [safeSelf dateForImageURL:url key:key]; + NSString *HTTPdate = [safeSelf httpDateForDate:lastUpdated]; + if (HTTPdate) { + [request addValue:HTTPdate forHTTPHeaderField:@"If-Modified-Since"]; + } + NSURLResponse* response = nil; NSError* error = nil; NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; @@ -85,9 +95,14 @@ - (void) _downloadAndWriteImageForURL:(NSURL *)url key:(NSString *)key completio }); return; } - - UIImage *i = [[UIImage alloc] initWithData:data]; - if (!i) + NSInteger kUnModifiedHttpCode = 304; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if (httpResponse.statusCode == kUnModifiedHttpCode) + { + return; + } + UIImage *imageDownloaded = [[UIImage alloc] initWithData:data]; + if (!imageDownloaded) { NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; [errorDetail setValue:[NSString stringWithFormat:@"Failed to init image with data from for URL: %@", url] forKey:NSLocalizedDescriptionKey]; @@ -102,33 +117,42 @@ - (void) _downloadAndWriteImageForURL:(NSURL *)url key:(NSString *)key completio NSString *cachePath = cachePathForKey(key); NSInvocation *writeInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(writeData:toPath:)]]; - [writeInvocation setTarget:self]; + [writeInvocation setTarget:safeSelf]; [writeInvocation setSelector:@selector(writeData:toPath:)]; [writeInvocation setArgument:&data atIndex:2]; [writeInvocation setArgument:&cachePath atIndex:3]; - [self performDiskWriteOperation:writeInvocation]; - [self setImage:i forKey:key]; + [safeSelf performDiskWriteOperation:writeInvocation]; + [safeSelf setImage:imageDownloaded forKey:key]; dispatch_async(dispatch_get_main_queue(), ^{ - if(completion) completion(i); + if(completion) completion(imageDownloaded); }); } }); } +- (NSString *)httpDateForDate:(NSDate *)lastUpdated { + NSDateFormatter* httpDateFormatter = [[NSDateFormatter alloc] init]; + httpDateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; + httpDateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + httpDateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + NSString *HTTPdate = [httpDateFormatter stringFromDate:lastUpdated]; + return HTTPdate; +} + - (void) removeAllObjects { [super removeAllObjects]; - + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSFileManager *fileMgr = [NSFileManager defaultManager]; NSError *error = nil; NSArray *directoryContents = [fileMgr contentsOfDirectoryAtPath:JMImageCacheDirectory() error:&error]; - + if (error == nil) { for (NSString *path in directoryContents) { NSString *fullPath = [JMImageCacheDirectory() stringByAppendingPathComponent:path]; - + BOOL removeSuccess = [fileMgr removeItemAtPath:fullPath error:&error]; if (!removeSuccess) { //Error Occured @@ -141,13 +165,13 @@ - (void) removeAllObjects { } - (void) removeObjectForKey:(id)key { [super removeObjectForKey:key]; - + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSFileManager *fileMgr = [NSFileManager defaultManager]; NSString *cachePath = cachePathForKey(key); - + NSError *error = nil; - + BOOL removeSuccess = [fileMgr removeItemAtPath:cachePath error:&error]; if (!removeSuccess) { //Error Occured @@ -159,15 +183,15 @@ - (void) removeObjectForKey:(id)key { #pragma mark Getter Methods - (void) imageForURL:(NSURL *)url key:(NSString *)key completionBlock:(void (^)(UIImage *image))completion failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failure{ - - UIImage *i = [self cachedImageForKey:key]; - - if (!i) { - i = [self cachedImageForURL:url]; + + UIImage *cachedImage = [self cachedImageForKey:key]; + + if (!cachedImage) { + cachedImage = [self cachedImageForURL:url]; } - if(i) { - if(completion) completion(i); + if(cachedImage) { + if(completion) completion(cachedImage); } else { [self _downloadAndWriteImageForURL:url key:key completionBlock:completion failureBlock:failure]; } @@ -179,18 +203,18 @@ - (void) imageForURL:(NSURL *)url completionBlock:(void (^)(UIImage *image))comp - (UIImage *) cachedImageForKey:(NSString *)key { if(!key) return nil; - + id returner = [super objectForKey:key]; - + if(returner) { return returner; } else { UIImage *i = [self imageFromDiskForKey:key]; if(i) [self setImage:i forKey:key]; - + return i; } - + return nil; } @@ -201,9 +225,9 @@ - (UIImage *) cachedImageForURL:(NSURL *)url { - (UIImage *) imageForURL:(NSURL *)url key:(NSString*)key delegate:(id)d { if(!url) return nil; - + UIImage *i = [self cachedImageForURL:url]; - + if(i) { return i; } else { @@ -217,9 +241,9 @@ - (UIImage *) imageForURL:(NSURL *)url key:(NSString*)key delegate:(id)d { } - (UIImage *) imageFromDiskForKey:(NSString *)key { - UIImage *i = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:cachePathForKey(key) options:0 error:NULL]]; + + NSString *pathToImage = cachePathForKey(key); + + UIImage *i = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:pathToImage options:0 error:NULL]]; return i; } +- (NSDate *)dateForImageURL:(NSURL *)url key:(NSString *)key { + + NSString *pathToImage = cachePathForKey(key); + + if(!pathToImage) + { + NSString *keyForPathToImage = keyForURL(url); + pathToImage = cachePathForKey(keyForPathToImage); + } + + if(!pathToImage) + return nil; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSDictionary* imageAttribute = [fileManager attributesOfItemAtPath:pathToImage error:nil]; + NSDate *lastUpdated = [imageAttribute fileModificationDate]; + + return lastUpdated; +} + - (UIImage *) imageFromDiskForURL:(NSURL *)url { return [self imageFromDiskForKey:keyForURL(url)]; } From c08de3bdd7104236feba78de482799daea44cd54 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Wed, 14 Aug 2013 17:29:07 +0100 Subject: [PATCH 08/13] now downloading the image with an if-unmodified http header even if found in cache. --- JMImageCache.m | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/JMImageCache.m b/JMImageCache.m index c43bf9c..dddd89a 100644 --- a/JMImageCache.m +++ b/JMImageCache.m @@ -77,7 +77,7 @@ - (void) _downloadAndWriteImageForURL:(NSURL *)url key:(NSString *)key completio NSMutableURLRequest* request = [NSURLRequest requestWithURL:url]; - NSDate *lastUpdated = [safeSelf dateForImageURL:url key:key]; + NSDate *lastUpdated = [safeSelf dateForImageKey:key]; NSString *HTTPdate = [safeSelf httpDateForDate:lastUpdated]; if (HTTPdate) { [request addValue:HTTPdate forHTTPHeaderField:@"If-Modified-Since"]; @@ -95,12 +95,14 @@ - (void) _downloadAndWriteImageForURL:(NSURL *)url key:(NSString *)key completio }); return; } + NSInteger kUnModifiedHttpCode = 304; NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == kUnModifiedHttpCode) { return; } + UIImage *imageDownloaded = [[UIImage alloc] initWithData:data]; if (!imageDownloaded) { @@ -186,15 +188,11 @@ - (void) imageForURL:(NSURL *)url key:(NSString *)key completionBlock:(void (^)( UIImage *cachedImage = [self cachedImageForKey:key]; - if (!cachedImage) { - cachedImage = [self cachedImageForURL:url]; - } - if(cachedImage) { if(completion) completion(cachedImage); - } else { - [self _downloadAndWriteImageForURL:url key:key completionBlock:completion failureBlock:failure]; } + [self _downloadAndWriteImageForURL:url key:key completionBlock:completion failureBlock:failure]; + } - (void) imageForURL:(NSURL *)url completionBlock:(void (^)(UIImage *image))completion failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failure{ @@ -259,16 +257,10 @@ - (UIImage *) imageFromDiskForKey:(NSString *)key { return i; } -- (NSDate *)dateForImageURL:(NSURL *)url key:(NSString *)key { +- (NSDate *)dateForImageKey:(NSString *)key { NSString *pathToImage = cachePathForKey(key); - - if(!pathToImage) - { - NSString *keyForPathToImage = keyForURL(url); - pathToImage = cachePathForKey(keyForPathToImage); - } - + if(!pathToImage) return nil; From 3493ece3b19111da7c683fe3200bac65ad841ca0 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Thu, 15 Aug 2013 11:33:15 +0100 Subject: [PATCH 09/13] not supporting ios4.3 anymore & using weak. Also using a nsmutableurlrequest to add if-unmodified-since header field to the request --- JMImageCache.m | 4 ++-- UIImageView+JMImageCache.m | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/JMImageCache.m b/JMImageCache.m index dddd89a..82b3972 100644 --- a/JMImageCache.m +++ b/JMImageCache.m @@ -70,12 +70,12 @@ - (void) _downloadAndWriteImageForURL:(NSURL *)url key:(NSString *)key completio key = keyForURL(url); } - __unsafe_unretained JMImageCache *safeSelf = self; + __weak JMImageCache *safeSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSMutableURLRequest* request = [NSURLRequest requestWithURL:url]; + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; NSDate *lastUpdated = [safeSelf dateForImageKey:key]; NSString *HTTPdate = [safeSelf httpDateForDate:lastUpdated]; diff --git a/UIImageView+JMImageCache.m b/UIImageView+JMImageCache.m index c4ab775..821e561 100644 --- a/UIImageView+JMImageCache.m +++ b/UIImageView+JMImageCache.m @@ -60,7 +60,7 @@ - (void) setImageWithURL:(NSURL *)url key:(NSString*)key placeholder:(UIImage *) self.jm_imageURL = url; [self assignImage:placeholderImage]; - __unsafe_unretained UIImageView *safeSelf = self; + __weak UIImageView *safeSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[JMImageCache sharedCache] imageForURL:url key:key completionBlock:^(UIImage *image) { From b0d14a74187c7d762268628594b0c2402db79212 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Thu, 15 Aug 2013 17:09:28 +0100 Subject: [PATCH 10/13] fixed issue with the empty key --- JMImageCache.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/JMImageCache.m b/JMImageCache.m index 82b3972..5040ee4 100644 --- a/JMImageCache.m +++ b/JMImageCache.m @@ -186,6 +186,10 @@ - (void) removeObjectForKey:(id)key { - (void) imageForURL:(NSURL *)url key:(NSString *)key completionBlock:(void (^)(UIImage *image))completion failureBlock:(void (^)(NSURLRequest *request, NSURLResponse *response, NSError* error))failure{ + if (!key) { + key = keyForURL(url); + } + UIImage *cachedImage = [self cachedImageForKey:key]; if(cachedImage) { From 557ca397938b9edb1b5967ffe5ca91972ed8cf15 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Fri, 16 Aug 2013 15:41:24 +0100 Subject: [PATCH 11/13] updated pod spec file --- JMImageCache.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JMImageCache.podspec b/JMImageCache.podspec index b061fa2..16b4574 100644 --- a/JMImageCache.podspec +++ b/JMImageCache.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "JMImageCache" - s.version = "0.4.0" + s.version = "0.4.1" s.summary = "NSCache based remote-image caching and downloading mechanism for iOS." s.description = 'NSCache based remote-image caching and downloading mechanism for iOS. Is block based and uses a simple UIImageView category to handle loading images with placeholders. With fix to the placeholder behaviour' @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.authors = { "Jake Marsh" => "jake@deallocatedobjects.com" } - s.source = { :git => "https://github.com/jakemarsh/JMImageCache.git", :tag => "0.4.0" } + s.source = { :git => "https://github.com/antoinerabanes/JMImageCache.git", :tag => s.version.to_s } s.platform = :ios, '5.0' s.requires_arc = true From 33345f38ea8f5fc9050fb84793348d5ae52b1f58 Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Tue, 10 Jun 2014 14:16:14 +0100 Subject: [PATCH 12/13] fixing this bloody warning :) --- JMImageCache.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JMImageCache.m b/JMImageCache.m index 5040ee4..a35ea0e 100644 --- a/JMImageCache.m +++ b/JMImageCache.m @@ -22,7 +22,7 @@ return [url absoluteString]; } static inline NSString *cachePathForKey(NSString *key) { - NSString *fileName = [NSString stringWithFormat:@"JMImageCache-%u", [key hash]]; + NSString *fileName = [NSString stringWithFormat:@"JMImageCache-%lu", (unsigned long)[key hash]]; return [JMImageCacheDirectory() stringByAppendingPathComponent:fileName]; } From 4f03a303be334e96692f4893528b8f35e0ed7f1e Mon Sep 17 00:00:00 2001 From: Antoine Rabanes Date: Mon, 23 Jun 2014 11:30:17 +0100 Subject: [PATCH 13/13] updated the pod spec to point to the new version --- Demo/JMImageCacheDemo.xcodeproj/project.pbxproj | 5 ++--- JMImageCache.podspec | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Demo/JMImageCacheDemo.xcodeproj/project.pbxproj b/Demo/JMImageCacheDemo.xcodeproj/project.pbxproj index 593613c..aba587d 100755 --- a/Demo/JMImageCacheDemo.xcodeproj/project.pbxproj +++ b/Demo/JMImageCacheDemo.xcodeproj/project.pbxproj @@ -168,7 +168,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0440; + LastUpgradeCheck = 0510; }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "JMImageCacheDemo" */; compatibilityVersion = "Xcode 3.2"; @@ -254,11 +254,11 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -266,7 +266,6 @@ C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; diff --git a/JMImageCache.podspec b/JMImageCache.podspec index 16b4574..984467c 100644 --- a/JMImageCache.podspec +++ b/JMImageCache.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "JMImageCache" - s.version = "0.4.1" + s.version = "0.4.2" s.summary = "NSCache based remote-image caching and downloading mechanism for iOS." s.description = 'NSCache based remote-image caching and downloading mechanism for iOS. Is block based and uses a simple UIImageView category to handle loading images with placeholders. With fix to the placeholder behaviour'