From ba818f0d65fe927b819aa43923e1b74148689afe Mon Sep 17 00:00:00 2001 From: andybee Date: Wed, 4 Apr 2012 21:19:57 +0200 Subject: [PATCH 1/3] Attempting to fix rs/SDWebImage#84 by passing success/failure blocks in user info dictionary. This avoids holding success and failure block in manager object which is used as a singleton by the UIImageView and UIButton additions classes, thus repeatedly calling the same block multiple times when making multiple requests. --- SDWebImageManager.m | 56 ++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/SDWebImageManager.m b/SDWebImageManager.m index b6f9bb49..e5afcec8 100644 --- a/SDWebImageManager.m +++ b/SDWebImageManager.m @@ -14,22 +14,12 @@ #if NS_BLOCKS_AVAILABLE typedef void(^SuccessBlock)(UIImage *image); typedef void(^FailureBlock)(NSError *error); - -@interface SDWebImageManager () -@property (nonatomic, copy) SuccessBlock successBlock; -@property (nonatomic, copy) FailureBlock failureBlock; -@end #endif static SDWebImageManager *instance; @implementation SDWebImageManager -#if NS_BLOCKS_AVAILABLE -@synthesize successBlock; -@synthesize failureBlock; -#endif - - (id)init { if ((self = [super init])) @@ -122,9 +112,29 @@ static SDWebImageManager *instance; #if NS_BLOCKS_AVAILABLE - (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure { - self.successBlock = success; - self.failureBlock = failure; - [self downloadWithURL:url delegate:delegate options:options]; + // repeated logic from above due to requirement for backwards compatability for iOS versions without blocks + + // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't + // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString. + if ([url isKindOfClass:NSString.class]) + { + url = [NSURL URLWithString:(NSString *)url]; + } + + if (!url || !delegate || (!(options & SDWebImageRetryFailed) && [failedURLs containsObject:url])) + { + return; + } + + // Check the on-disk cache async so we don't block the main thread + [cacheDelegates addObject:delegate]; + [cacheURLs addObject:url]; + SuccessBlock successCopy = Block_copy(success); + FailureBlock failureCopy = Block_copy(failure); + NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:delegate, @"delegate", url, @"url", [NSNumber numberWithInt:options], @"options", successCopy, @"success", failureCopy, @"failure", nil]; + Block_release(successCopy); + Block_release(failureCopy); + [[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString] delegate:self userInfo:info]; } #endif @@ -192,9 +202,10 @@ static SDWebImageManager *instance; objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:), self, image, url); } #if NS_BLOCKS_AVAILABLE - if (self.successBlock) + if ([info objectForKey:@"success"]) { - self.successBlock(image); + SuccessBlock success = [info objectForKey:@"success"]; + success(image); } #endif @@ -266,9 +277,10 @@ static SDWebImageManager *instance; objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:), self, image, downloader.url); } #if NS_BLOCKS_AVAILABLE - if (self.successBlock) + if ([downloader.userInfo objectForKey:@"success"]) { - self.successBlock(image); + SuccessBlock success = [downloader.userInfo objectForKey:@"success"]; + success(image); } #endif } @@ -283,9 +295,10 @@ static SDWebImageManager *instance; objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:), self, nil, downloader.url); } #if NS_BLOCKS_AVAILABLE - if (self.failureBlock) + if ([downloader.userInfo objectForKey:@"failure"]) { - self.failureBlock(nil); + FailureBlock failure = [downloader.userInfo objectForKey:@"failure"]; + failure(nil); } #endif } @@ -340,9 +353,10 @@ static SDWebImageManager *instance; objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:), self, error, downloader.url); } #if NS_BLOCKS_AVAILABLE - if (self.failureBlock) + if ([downloader.userInfo objectForKey:@"failure"]) { - self.failureBlock(error); + FailureBlock failure = [downloader.userInfo objectForKey:@"failure"]; + failure(error); } #endif From f87c057cb88f2b9c08ff512fcc153338c15b022e Mon Sep 17 00:00:00 2001 From: andybee Date: Wed, 4 Apr 2012 22:15:06 +0200 Subject: [PATCH 2/3] Made fix ARC-safe --- SDWebImageManager.m | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/SDWebImageManager.m b/SDWebImageManager.m index e5afcec8..685360be 100644 --- a/SDWebImageManager.m +++ b/SDWebImageManager.m @@ -129,11 +129,9 @@ static SDWebImageManager *instance; // Check the on-disk cache async so we don't block the main thread [cacheDelegates addObject:delegate]; [cacheURLs addObject:url]; - SuccessBlock successCopy = Block_copy(success); - FailureBlock failureCopy = Block_copy(failure); + SuccessBlock successCopy = SDWIAutorelease([success copy]); + FailureBlock failureCopy = SDWIAutorelease([failure copy]); NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:delegate, @"delegate", url, @"url", [NSNumber numberWithInt:options], @"options", successCopy, @"success", failureCopy, @"failure", nil]; - Block_release(successCopy); - Block_release(failureCopy); [[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString] delegate:self userInfo:info]; } #endif From 5cacab1b303f60e07625754a9f5d6e2455891819 Mon Sep 17 00:00:00 2001 From: andybee Date: Thu, 5 Apr 2012 10:24:46 +0200 Subject: [PATCH 3/3] Tweaked the safe release methodology for the copied blocks to remove un-necessary autorelease. --- SDWebImageManager.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SDWebImageManager.m b/SDWebImageManager.m index 685360be..a66d4fe0 100644 --- a/SDWebImageManager.m +++ b/SDWebImageManager.m @@ -129,9 +129,11 @@ static SDWebImageManager *instance; // Check the on-disk cache async so we don't block the main thread [cacheDelegates addObject:delegate]; [cacheURLs addObject:url]; - SuccessBlock successCopy = SDWIAutorelease([success copy]); - FailureBlock failureCopy = SDWIAutorelease([failure copy]); + SuccessBlock successCopy = [success copy]; + FailureBlock failureCopy = [failure copy]; NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:delegate, @"delegate", url, @"url", [NSNumber numberWithInt:options], @"options", successCopy, @"success", failureCopy, @"failure", nil]; + SDWIRelease(successCopy); + SDWIRelease(failureCopy); [[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString] delegate:self userInfo:info]; } #endif