From 28f720ea32a6fd606d52710da67053152bbd2e83 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 10:07:48 +0100 Subject: [PATCH 01/16] Add notice about 3.0 beta --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0469ab25e..6df50c1cf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Web Image ========= +> **Psst! [SDWebImage 3.0 beta](https://github.com/rs/SDWebImage/tree/3.0-beta) is out!** + This library provides a category for UIImageVIew with support for remote images coming from the web. It provides: @@ -12,6 +14,7 @@ It provides: - A guarantee that bogus URLs won't be retried again and again - Performances! + Motivation ---------- From 57f070061828c39ea2afcb2a1747390b4314fea2 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 10:12:26 +0100 Subject: [PATCH 02/16] Fix crash condition + invalid image orientation (fix #206) --- SDWebImage/MKAnnotationView+WebCache.m | 5 ++++- SDWebImage/SDWebImageCompat.h | 2 +- SDWebImage/UIButton+WebCache.m | 5 ++++- SDWebImage/UIImageView+WebCache.m | 5 ++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/SDWebImage/MKAnnotationView+WebCache.m b/SDWebImage/MKAnnotationView+WebCache.m index 0fe945702..affc6779a 100644 --- a/SDWebImage/MKAnnotationView+WebCache.m +++ b/SDWebImage/MKAnnotationView+WebCache.m @@ -64,7 +64,10 @@ - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder opt - (void)cancelCurrentImageLoad { - [[SDWebImageManager sharedManager] cancelForDelegate:self]; + @synchronized(self) + { + [[SDWebImageManager sharedManager] cancelForDelegate:self]; + } } - (void)webImageManager:(SDWebImageManager *)imageManager didProgressWithPartialImage:(UIImage *)image forURL:(NSURL *)url diff --git a/SDWebImage/SDWebImageCompat.h b/SDWebImage/SDWebImageCompat.h index 82d4c0ade..5fb9889a3 100644 --- a/SDWebImage/SDWebImageCompat.h +++ b/SDWebImage/SDWebImageCompat.h @@ -83,7 +83,7 @@ NS_INLINE UIImage *SDScaledImageForPath(NSString *path, NSObject *imageOrData) } } - UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:UIImageOrientationUp]; + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; SDWISafeRelease(image) image = scaledImage; } diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 2b61c1a8b..be6d3355f 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -129,7 +129,10 @@ - (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)place - (void)cancelCurrentImageLoad { - [[SDWebImageManager sharedManager] cancelForDelegate:self]; + @synchronized(self) + { + [[SDWebImageManager sharedManager] cancelForDelegate:self]; + } } - (void)webImageManager:(SDWebImageManager *)imageManager didProgressWithPartialImage:(UIImage *)image forURL:(NSURL *)url userInfo:(NSDictionary *)info diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index 090c82cda..de785ca73 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -64,7 +64,10 @@ - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder opt - (void)cancelCurrentImageLoad { - [[SDWebImageManager sharedManager] cancelForDelegate:self]; + @synchronized(self) + { + [[SDWebImageManager sharedManager] cancelForDelegate:self]; + } } - (void)webImageManager:(SDWebImageManager *)imageManager didProgressWithPartialImage:(UIImage *)image forURL:(NSURL *)url From 2b2af218a5d67fee4c08a8bb0ca1fa663a03ed77 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 15:16:49 +0100 Subject: [PATCH 03/16] Add who use it section --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6df50c1cf..e83ce2279 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,13 @@ the reason for this lagging issue. Actually I first used NSOperation to workarou This technique combined with an image cache instantly gave a lot of responsiveness to my app. I thought this library could benefit other Cocoa Touch applications so I open-sourced it. -How To Use It -------------- +Who Use It +---------- + +Find out [who use SDWebImage](https://github.com/rs/SDWebImage/wiki/Who-Use-SDWebImage) and add your app to the list. + +How To Use +---------- API documentation is available at [http://hackemist.com/SDWebImage/doc/](http://hackemist.com/SDWebImage/doc/) From e99e1b97e94791cdc531974c453dba0f9a5cdc3e Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 15:39:50 +0100 Subject: [PATCH 04/16] Remove outdated motivation section --- README.md | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/README.md b/README.md index e83ce2279..72cfd0205 100644 --- a/README.md +++ b/README.md @@ -15,49 +15,6 @@ It provides: - Performances! -Motivation ----------- - -As a dummy Objective-C developer working on my first iPhone application for my company -([Dailymotion][]), I've been very frustrated by the lack of support in the Cocoa Touch framework for -UITableView with remote images. After some Googling, I found lot of forums and blogs coming up with -their solution, most of the time based on asynchronous usage with NSURLConnection, but none provided -a simple library doing the work of async image grabbing + caching for you. - -Actually there is one in the famous [Three20][] framework by [Joe Hewitt][], but it's a massive -and undocumented piece of code. You can't import just the the libraries you want without taking the -whole framework (damn #import "TTGlobal.h"). Anyway, the [Three20][] implementation is based on -NSURLConnection, and I soon discovered this solution wasn't ideal. Keep reading to find out why. - -As a hurried beginner in iPhone development, I couldn't attempt to implement my own async image -grabber with caching support as my first steps in this new world. Thus, I asked for help from my good -friend Sebastien Flory ([Fraggle][]), who was working on his great iPhone game ([Urban Rivals][], a -future app-store hit) for almost a year. He spent quite an amount of time implementing the very -same solution for his needs, and was kind enough to give me his implementation for my own use. This -worked quite well and allowed me to concentrate on other parts of my application. But when I started -to compare my application with its direct competitor - the built-in Youtube application - I was very -unhappy with the loading speed of the images. After some network sniffing, I found that every HTTP -requests for my images was 10 times slower than Youtube's... On my own network, Youtube was 10 -time faster than my own servers... WTF?? - -In fact, my servers were fine but a lot of latency was added to the requests, certainly because my -application wasn't responsive enough to handle the requests at full speed. Right then, I -understood something important, asynchronous NSURLConnections are tied to the main runloop in the -NSEventTrackingRunLoopMode. As explained in the documentation, this runloop mode is affected by -UI events: - -> Cocoa uses this mode to restrict incoming events during mouse-dragging loops and other sorts of -> user interface tracking loops. - -A simple test to recognize an application using NSURLConnection in its default mode to load -remote images is to scroll the UITableView with your finger to disclose an unloaded image, and to -keep your finger pressed on the screen. If the image doesn't load until you release you finger, -you've got one (try with the Facebook app for instance). It took me quite some time to understand -the reason for this lagging issue. Actually I first used NSOperation to workaround this issue. - -This technique combined with an image cache instantly gave a lot of responsiveness to my app. -I thought this library could benefit other Cocoa Touch applications so I open-sourced it. - Who Use It ---------- @@ -260,10 +217,3 @@ Future Enhancements ------------------- - LRU memory cache cleanup instead of reset on memory warning - -[Dailymotion]: http://www.dailymotion.com -[Fraggle]: http://fraggle.squarespace.com -[Urban Rivals]: http://fraggle.squarespace.com/blog/2009/9/15/almost-done-here-is-urban-rivals-iphone-trailer.html -[Three20]: http://groups.google.com/group/three20 -[Joe Hewitt]: http://www.joehewitt.com -[tutorial]: http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4 From eff17b831754aa21af9413012bcdca3909b9410f Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 15:42:49 +0100 Subject: [PATCH 05/16] Sync feature list with 3.0 README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 72cfd0205..d44e51b42 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,12 @@ It provides: - An UIImageView category adding web image and cache management to the Cocoa Touch framework - An asynchronous image downloader - An asynchronous memory + disk image caching with automatic cache expiration handling +- A background image decompression - A guarantee that the same URL won't be downloaded several times - A guarantee that bogus URLs won't be retried again and again +- A guarantee that main thread will never be blocked - Performances! - Who Use It ---------- From 94c52e3975cd119ee69e31ffbe294539bd8dc2b4 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 16:17:01 +0100 Subject: [PATCH 06/16] Add "How is SDWebImage better than X?" wiki link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d44e51b42..5fd85afb6 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ It provides: - A guarantee that main thread will never be blocked - Performances! +[How is SDWebImage better than X?](https://github.com/rs/SDWebImage/wiki/How-is-SDWebImage-better-than-X%3F) + Who Use It ---------- From 28f6d7eae219c02d46eef018f76b5292d81a8289 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sun, 4 Nov 2012 17:47:56 +0100 Subject: [PATCH 07/16] Add Licenses section --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5fd85afb6..a1266d6ac 100644 --- a/README.md +++ b/README.md @@ -220,3 +220,7 @@ Future Enhancements ------------------- - LRU memory cache cleanup instead of reset on memory warning + +## Licenses + +All source code is licensed under the [MIT-License](https://raw.github.com/rs/SDWebImage/master/MIT-LICENSE). From f58453da01e2b12a747c4bf8389a6c8dc74dc02c Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Mon, 5 Nov 2012 12:20:18 +0100 Subject: [PATCH 08/16] Fix typo in license URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1266d6ac..b4da06974 100644 --- a/README.md +++ b/README.md @@ -223,4 +223,4 @@ Future Enhancements ## Licenses -All source code is licensed under the [MIT-License](https://raw.github.com/rs/SDWebImage/master/MIT-LICENSE). +All source code is licensed under the [MIT License](https://raw.github.com/rs/SDWebImage/master/LICENSE). From 980226ccb78754e02a4cf665283d48a338082e2d Mon Sep 17 00:00:00 2001 From: herrernst Date: Mon, 5 Nov 2012 17:20:33 +0100 Subject: [PATCH 09/16] prevent caching of responses in Cache.db --- SDWebImage/SDWebImageDownloader.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 6285880e7..c99b0572e 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -253,6 +253,12 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err self.imageData = nil; } +//prevent caching of responses in Cache.db +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse +{ + return nil; +} + #pragma mark SDWebImageDecoderDelegate - (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)aUserInfo From f03729c9cae860f3b8860ac67b39b7260f2253d5 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Mon, 5 Nov 2012 17:53:11 +0100 Subject: [PATCH 10/16] Fix wrong cache policy used (fix #211) --- SDWebImage/SDWebImageDownloader.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageDownloader.m b/SDWebImage/SDWebImageDownloader.m index 6285880e7..d004d3d1a 100644 --- a/SDWebImage/SDWebImageDownloader.m +++ b/SDWebImage/SDWebImageDownloader.m @@ -76,7 +76,7 @@ + (void)setMaxConcurrentDownloads:(NSUInteger)max - (void)start { // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests - NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; + NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:15]; self.connection = SDWIReturnAutoreleased([[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]); // If not in low priority mode, ensure we aren't blocked by UI manipulations (default runloop mode for NSURLConnection is NSEventTrackingRunLoopMode) From 65d28ab2946ca841f98a6d2d2400d56617d66105 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Mon, 12 Nov 2012 00:05:19 +0100 Subject: [PATCH 11/16] Fix CGBitmapContextCreate errors (fix #204) --- SDWebImage/SDWebImageDecoder.m | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/SDWebImage/SDWebImageDecoder.m b/SDWebImage/SDWebImageDecoder.m index fe10d0be0..9a5346868 100644 --- a/SDWebImage/SDWebImageDecoder.m +++ b/SDWebImage/SDWebImageDecoder.m @@ -96,36 +96,17 @@ @implementation UIImage (ForceDecode) + (UIImage *)decodedImageWithImage:(UIImage *)image { - CGImageRef imageRef = image.CGImage; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); - + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image.CGImage); BOOL imageHasAlphaInfo = (alphaInfo != kCGImageAlphaNone && alphaInfo != kCGImageAlphaNoneSkipFirst && alphaInfo != kCGImageAlphaNoneSkipLast); - int bytesPerPixel = alphaInfo != kCGImageAlphaNone ? 4 : 3; - CGBitmapInfo bitmapInfo = imageHasAlphaInfo ? kCGImageAlphaPremultipliedLast : alphaInfo; - - CGContextRef context = CGBitmapContextCreate(NULL, - CGImageGetWidth(imageRef), - CGImageGetHeight(imageRef), - 8, - // Just always return width * bytesPerPixel will be enough - CGImageGetWidth(imageRef) * bytesPerPixel, - // System only supports RGB, set explicitly - colorSpace, - bitmapInfo); - CGColorSpaceRelease(colorSpace); - if (!context) return nil; - - CGRect rect = (CGRect){CGPointZero,{CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)}}; - CGContextDrawImage(context, rect, imageRef); - CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context); - CGContextRelease(context); - - UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation]; - CGImageRelease(decompressedImageRef); + UIGraphicsBeginImageContextWithOptions(image.size, !imageHasAlphaInfo, 0); + CGRect rect = (CGRect){.origin = CGPointZero, .size = image.size}; + [image drawInRect:rect]; + UIImage *decompressedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return SDWIReturnAutoreleased(decompressedImage); } From 1443ffe11bfdaf275ae93d0365544ec06c14160c Mon Sep 17 00:00:00 2001 From: Javier Soto Date: Tue, 13 Nov 2012 16:05:50 -0800 Subject: [PATCH 12/16] Fixing overrelease of UIImage object --- SDWebImage/SDWebImageDecoder.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDWebImage/SDWebImageDecoder.m b/SDWebImage/SDWebImageDecoder.m index 9a5346868..5505f2edb 100644 --- a/SDWebImage/SDWebImageDecoder.m +++ b/SDWebImage/SDWebImageDecoder.m @@ -107,7 +107,7 @@ + (UIImage *)decodedImageWithImage:(UIImage *)image UIImage *decompressedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - return SDWIReturnAutoreleased(decompressedImage); + return decompressedImage; } @end From 7f966ae69c3eb4f50f661ab332f64e95800a92b8 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Thu, 6 Dec 2012 09:25:13 +0100 Subject: [PATCH 13/16] Remove beta notice --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b4da06974..19806a524 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ Web Image ========= -> **Psst! [SDWebImage 3.0 beta](https://github.com/rs/SDWebImage/tree/3.0-beta) is out!** - This library provides a category for UIImageVIew with support for remote images coming from the web. It provides: From 0c2c9965f09e4fafcd24d03ec602c130579ef416 Mon Sep 17 00:00:00 2001 From: liuzhenfu Date: Wed, 24 Apr 2013 14:47:37 +0800 Subject: [PATCH 14/16] Fixed bugs when delegates add/cancel requests from delegate callbacks Fixed bugs where callbacks via delegates or blocks could cause a crash since these might modify the downloaders, downloadInfo or downloadDelegates arrays if adding a new download request or canceling one from these. https://github.com/rs/SDWebImage/pull/139 --- SDWebImage/SDWebImageManager.m | 139 +++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 43 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index ab76576f3..1f96d92ce 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -181,6 +181,18 @@ - (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOp } #endif +- (void)removeObjectsForDelegate:(id)delegate +{ + // Delegates notified, remove downloader and delegate + // The delegate callbacks above may have modified the arrays, hence we search for the correct index + int idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]; + if (idx != NSNotFound) { + [downloaders removeObjectAtIndex:idx]; + [downloadInfo removeObjectAtIndex:idx]; + [downloadDelegates removeObjectAtIndex:idx]; + } +} + - (void)cancelForDelegate:(id)delegate { NSUInteger idx; @@ -276,9 +288,14 @@ - (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forK success(image, YES); } #endif - - [cacheDelegates removeObjectAtIndex:idx]; - [cacheURLs removeObjectAtIndex:idx]; + + // Delegates notified, remove url and delegate + // The delegate callbacks above may have modified the arrays, hence we search for the correct index + int removeIdx = [self indexOfDelegate:delegate waitingForURL:url]; + if (removeIdx != NSNotFound) { + [cacheDelegates removeObjectAtIndex:removeIdx]; + [cacheURLs removeObjectAtIndex:removeIdx]; + } } - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info @@ -326,16 +343,34 @@ - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *) - (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage:(UIImage *)image { - // Notify all the downloadDelegates with this downloader - for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--) - { - NSUInteger uidx = (NSUInteger)idx; - SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx]; - if (aDownloader == downloader) + NSMutableArray *notifiedDelegates = [NSMutableArray arrayWithCapacity:downloaders.count]; + + BOOL found = YES; + while (found) { + found = NO; + assert(downloaders.count == downloadDelegates.count); + assert(downloaders.count == downloadInfo.count); + NSInteger count = downloaders.count; + for (NSInteger i=count-1; i>=0; --i) { - id delegate = [downloadDelegates objectAtIndex:uidx]; + SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; + if (aDownloader != downloader) { + continue; + } + + id delegate = [downloadDelegates objectAtIndex:i]; SDWIRetain(delegate); SDWIAutorelease(delegate); + + if ([notifiedDelegates containsObject:delegate]) { + continue; + } + // Keep track of delegates notified + [notifiedDelegates addObject:delegate]; + + NSDictionary *info = [downloadInfo objectAtIndex:i]; + SDWIRetain(info); + SDWIAutorelease(info); if ([delegate respondsToSelector:@selector(webImageManager:didProgressWithPartialImage:forURL:)]) { @@ -343,13 +378,16 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage } if ([delegate respondsToSelector:@selector(webImageManager:didProgressWithPartialImage:forURL:userInfo:)]) { - NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"]; + NSDictionary *userInfo = [info objectForKey:@"userInfo"]; if ([userInfo isKindOfClass:NSNull.class]) { userInfo = nil; } objc_msgSend(delegate, @selector(webImageManager:didProgressWithPartialImage:forURL:userInfo:), self, image, downloader.url, userInfo); } + // Delegate notified. Break out and restart loop + found = YES; + break; } } } @@ -358,17 +396,23 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U { SDWIRetain(downloader); SDWebImageOptions options = [[downloader.userInfo objectForKey:@"options"] intValue]; - - // Notify all the downloadDelegates with this downloader - for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--) - { - NSUInteger uidx = (NSUInteger)idx; - SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx]; - if (aDownloader == downloader) - { - id delegate = [downloadDelegates objectAtIndex:uidx]; + BOOL found = YES; + while (found) { + found = NO; + assert(downloaders.count == downloadDelegates.count); + assert(downloaders.count == downloadInfo.count); + NSInteger count = downloaders.count; + for (NSInteger i=count-1; i>=0; --i) { + SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; + if (aDownloader != downloader) { + continue; + } + id delegate = [downloadDelegates objectAtIndex:i]; SDWIRetain(delegate); SDWIAutorelease(delegate); + NSDictionary *info = [downloadInfo objectAtIndex:i]; + SDWIRetain(info); + SDWIAutorelease(info); if (image) { @@ -382,7 +426,7 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U } if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:userInfo:)]) { - NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"]; + NSDictionary *userInfo = [info objectForKey:@"userInfo"]; if ([userInfo isKindOfClass:NSNull.class]) { userInfo = nil; @@ -390,9 +434,9 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:userInfo:), self, image, downloader.url, userInfo); } #if NS_BLOCKS_AVAILABLE - if ([[downloadInfo objectAtIndex:uidx] objectForKey:@"success"]) + if ([info objectForKey:@"success"]) { - SDWebImageSuccessBlock success = [[downloadInfo objectAtIndex:uidx] objectForKey:@"success"]; + SDWebImageSuccessBlock success = [info objectForKey:@"success"]; success(image, NO); } #endif @@ -409,7 +453,7 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U } if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:userInfo:)]) { - NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"]; + NSDictionary *userInfo = [info objectForKey:@"userInfo"]; if ([userInfo isKindOfClass:NSNull.class]) { userInfo = nil; @@ -417,17 +461,17 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:userInfo:), self, nil, downloader.url, userInfo); } #if NS_BLOCKS_AVAILABLE - if ([[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"]) + if ([info objectForKey:@"failure"]) { - SDWebImageFailureBlock failure = [[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"]; + SDWebImageFailureBlock failure = [info objectForKey:@"failure"]; failure(nil); } #endif } - - [downloaders removeObjectAtIndex:uidx]; - [downloadInfo removeObjectAtIndex:uidx]; - [downloadDelegates removeObjectAtIndex:uidx]; + // Downloader found. Break out and restart for loop + [self removeObjectsForDelegate:delegate]; + found = YES; + break; } } @@ -457,15 +501,24 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSE SDWIRetain(downloader); // Notify all the downloadDelegates with this downloader - for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--) - { - NSUInteger uidx = (NSUInteger)idx; - SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx]; - if (aDownloader == downloader) + BOOL found = YES; + while (found) { + found = NO; + assert(downloaders.count == downloadDelegates.count); + assert(downloaders.count == downloadInfo.count); + NSInteger count = downloaders.count; + for (NSInteger i=count-1 ; i>=0; --i) { - id delegate = [downloadDelegates objectAtIndex:uidx]; + SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; + if (aDownloader != downloader) { + continue; + } + id delegate = [downloadDelegates objectAtIndex:i]; SDWIRetain(delegate); SDWIAutorelease(delegate); + NSDictionary *info = [downloadInfo objectAtIndex:i]; + SDWIRetain(info); + SDWIAutorelease(info); if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]) { @@ -477,7 +530,7 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSE } if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:userInfo:)]) { - NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"]; + NSDictionary *userInfo = [info objectForKey:@"userInfo"]; if ([userInfo isKindOfClass:NSNull.class]) { userInfo = nil; @@ -485,16 +538,16 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSE objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:userInfo:), self, error, downloader.url, userInfo); } #if NS_BLOCKS_AVAILABLE - if ([[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"]) + if ([info objectForKey:@"failure"]) { - SDWebImageFailureBlock failure = [[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"]; + SDWebImageFailureBlock failure = [info objectForKey:@"failure"]; failure(error); } #endif - - [downloaders removeObjectAtIndex:uidx]; - [downloadInfo removeObjectAtIndex:uidx]; - [downloadDelegates removeObjectAtIndex:uidx]; + // Downloader found. Break out and restart for loop + [self removeObjectsForDelegate:delegate]; + found = YES; + break; } } From 94acdcd527b5a261415e78d69d35f524dcd9c657 Mon Sep 17 00:00:00 2001 From: liuzhenfu Date: Sun, 28 Apr 2013 01:12:17 +0800 Subject: [PATCH 15/16] format the code to the right indentation. --- SDWebImage/SDWebImageManager.m | 214 ++++++++++++++++----------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 1f96d92ce..8e8779e0b 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -53,7 +53,7 @@ + (id)sharedManager { instance = [[SDWebImageManager alloc] init]; } - + return instance; } @@ -122,12 +122,12 @@ - (void)downloadWithURL:(NSURL *)url delegate:(id)del { url = nil; // Prevent some common crashes due to common wrong values passed like NSNull.null for instance } - + 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]; @@ -183,14 +183,14 @@ - (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOp - (void)removeObjectsForDelegate:(id)delegate { - // Delegates notified, remove downloader and delegate - // The delegate callbacks above may have modified the arrays, hence we search for the correct index - int idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]; - if (idx != NSNotFound) { - [downloaders removeObjectAtIndex:idx]; - [downloadInfo removeObjectAtIndex:idx]; - [downloadDelegates removeObjectAtIndex:idx]; - } + // Delegates notified, remove downloader and delegate + // The delegate callbacks above may have modified the arrays, hence we search for the correct index + int idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]; + if (idx != NSNotFound) { + [downloaders removeObjectAtIndex:idx]; + [downloadInfo removeObjectAtIndex:idx]; + [downloadDelegates removeObjectAtIndex:idx]; + } } - (void)cancelForDelegate:(id)delegate @@ -201,22 +201,22 @@ - (void)cancelForDelegate:(id)delegate [cacheDelegates removeObjectAtIndex:idx]; [cacheURLs removeObjectAtIndex:idx]; } - + while ((idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]) != NSNotFound) { SDWebImageDownloader *downloader = SDWIReturnRetained([downloaders objectAtIndex:idx]); - + [downloadInfo removeObjectAtIndex:idx]; [downloadDelegates removeObjectAtIndex:idx]; [downloaders removeObjectAtIndex:idx]; - + if (![downloaders containsObject:downloader]) { // No more delegate are waiting for this download, cancel it [downloader cancel]; [downloaderForURL removeObjectForKey:downloader.url]; } - + SDWIRelease(downloader); } } @@ -229,7 +229,7 @@ - (void)cancelAll } [cacheDelegates removeAllObjects]; [cacheURLs removeAllObjects]; - + [downloadInfo removeAllObjects]; [downloadDelegates removeAllObjects]; [downloaders removeAllObjects]; @@ -256,14 +256,14 @@ - (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forK { NSURL *url = [info objectForKey:@"url"]; id delegate = [info objectForKey:@"delegate"]; - + NSUInteger idx = [self indexOfDelegate:delegate waitingForURL:url]; if (idx == NSNotFound) { // Request has since been canceled return; } - + if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]) { [delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image]; @@ -288,14 +288,14 @@ - (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forK success(image, YES); } #endif - - // Delegates notified, remove url and delegate - // The delegate callbacks above may have modified the arrays, hence we search for the correct index - int removeIdx = [self indexOfDelegate:delegate waitingForURL:url]; - if (removeIdx != NSNotFound) { - [cacheDelegates removeObjectAtIndex:removeIdx]; - [cacheURLs removeObjectAtIndex:removeIdx]; - } + + // Delegates notified, remove url and delegate + // The delegate callbacks above may have modified the arrays, hence we search for the correct index + int removeIdx = [self indexOfDelegate:delegate waitingForURL:url]; + if (removeIdx != NSNotFound) { + [cacheDelegates removeObjectAtIndex:removeIdx]; + [cacheURLs removeObjectAtIndex:removeIdx]; + } } - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info @@ -303,20 +303,20 @@ - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *) NSURL *url = [info objectForKey:@"url"]; id delegate = [info objectForKey:@"delegate"]; SDWebImageOptions options = [[info objectForKey:@"options"] intValue]; - + NSUInteger idx = [self indexOfDelegate:delegate waitingForURL:url]; if (idx == NSNotFound) { // Request has since been canceled return; } - + [cacheDelegates removeObjectAtIndex:idx]; [cacheURLs removeObjectAtIndex:idx]; - + // Share the same downloader for identical URLs so we don't download the same URL several times SDWebImageDownloader *downloader = [downloaderForURL objectForKey:url]; - + if (!downloader) { downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self userInfo:info lowPriority:(options & SDWebImageLowPriority)]; @@ -327,13 +327,13 @@ - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *) // Reuse shared downloader downloader.lowPriority = (options & SDWebImageLowPriority); } - + if ((options & SDWebImageProgressiveDownload) && !downloader.progressive) { // Turn progressive download support on demand downloader.progressive = YES; } - + [downloadInfo addObject:info]; [downloadDelegates addObject:delegate]; [downloaders addObject:downloader]; @@ -343,51 +343,51 @@ - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *) - (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage:(UIImage *)image { - NSMutableArray *notifiedDelegates = [NSMutableArray arrayWithCapacity:downloaders.count]; - - BOOL found = YES; - while (found) { - found = NO; - assert(downloaders.count == downloadDelegates.count); - assert(downloaders.count == downloadInfo.count); - NSInteger count = downloaders.count; - for (NSInteger i=count-1; i>=0; --i) + NSMutableArray *notifiedDelegates = [NSMutableArray arrayWithCapacity:downloaders.count]; + + BOOL found = YES; + while (found) { + found = NO; + assert(downloaders.count == downloadDelegates.count); + assert(downloaders.count == downloadInfo.count); + NSInteger count = downloaders.count; + for (NSInteger i=count-1; i>=0; --i) { - SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; - if (aDownloader != downloader) { - continue; - } - - id delegate = [downloadDelegates objectAtIndex:i]; + SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; + if (aDownloader != downloader) { + continue; + } + + id delegate = [downloadDelegates objectAtIndex:i]; SDWIRetain(delegate); SDWIAutorelease(delegate); - - if ([notifiedDelegates containsObject:delegate]) { - continue; - } - // Keep track of delegates notified - [notifiedDelegates addObject:delegate]; - - NSDictionary *info = [downloadInfo objectAtIndex:i]; - SDWIRetain(info); - SDWIAutorelease(info); - + + if ([notifiedDelegates containsObject:delegate]) { + continue; + } + // Keep track of delegates notified + [notifiedDelegates addObject:delegate]; + + NSDictionary *info = [downloadInfo objectAtIndex:i]; + SDWIRetain(info); + SDWIAutorelease(info); + if ([delegate respondsToSelector:@selector(webImageManager:didProgressWithPartialImage:forURL:)]) { objc_msgSend(delegate, @selector(webImageManager:didProgressWithPartialImage:forURL:), self, image, downloader.url); } if ([delegate respondsToSelector:@selector(webImageManager:didProgressWithPartialImage:forURL:userInfo:)]) { - NSDictionary *userInfo = [info objectForKey:@"userInfo"]; + NSDictionary *userInfo = [info objectForKey:@"userInfo"]; if ([userInfo isKindOfClass:NSNull.class]) { userInfo = nil; } objc_msgSend(delegate, @selector(webImageManager:didProgressWithPartialImage:forURL:userInfo:), self, image, downloader.url, userInfo); } - // Delegate notified. Break out and restart loop - found = YES; - break; + // Delegate notified. Break out and restart loop + found = YES; + break; } } } @@ -396,24 +396,24 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U { SDWIRetain(downloader); SDWebImageOptions options = [[downloader.userInfo objectForKey:@"options"] intValue]; - BOOL found = YES; - while (found) { - found = NO; - assert(downloaders.count == downloadDelegates.count); - assert(downloaders.count == downloadInfo.count); - NSInteger count = downloaders.count; - for (NSInteger i=count-1; i>=0; --i) { - SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; - if (aDownloader != downloader) { - continue; - } - id delegate = [downloadDelegates objectAtIndex:i]; + BOOL found = YES; + while (found) { + found = NO; + assert(downloaders.count == downloadDelegates.count); + assert(downloaders.count == downloadInfo.count); + NSInteger count = downloaders.count; + for (NSInteger i=count-1; i>=0; --i) { + SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; + if (aDownloader != downloader) { + continue; + } + id delegate = [downloadDelegates objectAtIndex:i]; SDWIRetain(delegate); SDWIAutorelease(delegate); - NSDictionary *info = [downloadInfo objectAtIndex:i]; - SDWIRetain(info); - SDWIAutorelease(info); - + NSDictionary *info = [downloadInfo objectAtIndex:i]; + SDWIRetain(info); + SDWIAutorelease(info); + if (image) { if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]) @@ -468,13 +468,13 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U } #endif } - // Downloader found. Break out and restart for loop - [self removeObjectsForDelegate:delegate]; - found = YES; - break; + // Downloader found. Break out and restart for loop + [self removeObjectsForDelegate:delegate]; + found = YES; + break; } } - + if (image) { // Store the image in the cache @@ -489,8 +489,8 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U // (do this only if SDWebImageRetryFailed isn't activated) [failedURLs addObject:downloader.url]; } - - + + // Release the downloader [downloaderForURL removeObjectForKey:downloader.url]; SDWIRelease(downloader); @@ -499,27 +499,27 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error; { SDWIRetain(downloader); - + // Notify all the downloadDelegates with this downloader - BOOL found = YES; - while (found) { - found = NO; - assert(downloaders.count == downloadDelegates.count); - assert(downloaders.count == downloadInfo.count); - NSInteger count = downloaders.count; - for (NSInteger i=count-1 ; i>=0; --i) + BOOL found = YES; + while (found) { + found = NO; + assert(downloaders.count == downloadDelegates.count); + assert(downloaders.count == downloadInfo.count); + NSInteger count = downloaders.count; + for (NSInteger i=count-1 ; i>=0; --i) { - SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; - if (aDownloader != downloader) { - continue; - } - id delegate = [downloadDelegates objectAtIndex:i]; + SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; + if (aDownloader != downloader) { + continue; + } + id delegate = [downloadDelegates objectAtIndex:i]; SDWIRetain(delegate); SDWIAutorelease(delegate); - NSDictionary *info = [downloadInfo objectAtIndex:i]; - SDWIRetain(info); - SDWIAutorelease(info); - + NSDictionary *info = [downloadInfo objectAtIndex:i]; + SDWIRetain(info); + SDWIAutorelease(info); + if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]) { [delegate performSelector:@selector(webImageManager:didFailWithError:) withObject:self withObject:error]; @@ -544,13 +544,13 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSE failure(error); } #endif - // Downloader found. Break out and restart for loop - [self removeObjectsForDelegate:delegate]; - found = YES; - break; + // Downloader found. Break out and restart for loop + [self removeObjectsForDelegate:delegate]; + found = YES; + break; } } - + // Release the downloader [downloaderForURL removeObjectForKey:downloader.url]; SDWIRelease(downloader); From 95ef42d48c979223b3414c5a50ebee40659c9663 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Sat, 27 Apr 2013 19:21:18 +0200 Subject: [PATCH 16/16] Fix code format --- SDWebImage/SDWebImageManager.m | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 8e8779e0b..a2087f164 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -186,7 +186,8 @@ - (void)removeObjectsForDelegate:(id)delegate // Delegates notified, remove downloader and delegate // The delegate callbacks above may have modified the arrays, hence we search for the correct index int idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]; - if (idx != NSNotFound) { + if (idx != NSNotFound) + { [downloaders removeObjectAtIndex:idx]; [downloadInfo removeObjectAtIndex:idx]; [downloadDelegates removeObjectAtIndex:idx]; @@ -292,7 +293,8 @@ - (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forK // Delegates notified, remove url and delegate // The delegate callbacks above may have modified the arrays, hence we search for the correct index int removeIdx = [self indexOfDelegate:delegate waitingForURL:url]; - if (removeIdx != NSNotFound) { + if (removeIdx != NSNotFound) + { [cacheDelegates removeObjectAtIndex:removeIdx]; [cacheURLs removeObjectAtIndex:removeIdx]; } @@ -346,7 +348,8 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage NSMutableArray *notifiedDelegates = [NSMutableArray arrayWithCapacity:downloaders.count]; BOOL found = YES; - while (found) { + while (found) + { found = NO; assert(downloaders.count == downloadDelegates.count); assert(downloaders.count == downloadInfo.count); @@ -354,7 +357,8 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage for (NSInteger i=count-1; i>=0; --i) { SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; - if (aDownloader != downloader) { + if (aDownloader != downloader) + { continue; } @@ -362,7 +366,8 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage SDWIRetain(delegate); SDWIAutorelease(delegate); - if ([notifiedDelegates containsObject:delegate]) { + if ([notifiedDelegates containsObject:delegate]) + { continue; } // Keep track of delegates notified @@ -397,14 +402,17 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(U SDWIRetain(downloader); SDWebImageOptions options = [[downloader.userInfo objectForKey:@"options"] intValue]; BOOL found = YES; - while (found) { + while (found) + { found = NO; assert(downloaders.count == downloadDelegates.count); assert(downloaders.count == downloadInfo.count); NSInteger count = downloaders.count; - for (NSInteger i=count-1; i>=0; --i) { + for (NSInteger i=count-1; i>=0; --i) + { SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; - if (aDownloader != downloader) { + if (aDownloader != downloader) + { continue; } id delegate = [downloadDelegates objectAtIndex:i]; @@ -502,7 +510,8 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSE // Notify all the downloadDelegates with this downloader BOOL found = YES; - while (found) { + while (found) + { found = NO; assert(downloaders.count == downloadDelegates.count); assert(downloaders.count == downloadInfo.count); @@ -510,7 +519,8 @@ - (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSE for (NSInteger i=count-1 ; i>=0; --i) { SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i]; - if (aDownloader != downloader) { + if (aDownloader != downloader) + { continue; } id delegate = [downloadDelegates objectAtIndex:i];