diff --git a/SDWebImageManager.h b/SDWebImageManager.h index 40b7be9a..f5578756 100644 --- a/SDWebImageManager.h +++ b/SDWebImageManager.h @@ -13,8 +13,9 @@ @interface SDWebImageManager : NSObject { - NSMutableArray *delegates; + NSMutableArray *downloadDelegates; NSMutableArray *downloaders; + NSMutableArray *cacheDelegates; NSMutableDictionary *downloaderForURL; NSMutableArray *failedURLs; } diff --git a/SDWebImageManager.m b/SDWebImageManager.m index e4ea1c95..9c6ddbc5 100644 --- a/SDWebImageManager.m +++ b/SDWebImageManager.m @@ -18,8 +18,9 @@ static SDWebImageManager *instance; { if ((self = [super init])) { - delegates = [[NSMutableArray alloc] init]; + downloadDelegates = [[NSMutableArray alloc] init]; downloaders = [[NSMutableArray alloc] init]; + cacheDelegates = [[NSMutableArray alloc] init]; downloaderForURL = [[NSMutableDictionary alloc] init]; failedURLs = [[NSMutableArray alloc] init]; } @@ -28,8 +29,9 @@ static SDWebImageManager *instance; - (void)dealloc { - [delegates release], delegates = nil; + [downloadDelegates release], downloadDelegates = nil; [downloaders release], downloaders = nil; + [cacheDelegates release], cacheDelegates = nil; [downloaderForURL release], downloaderForURL = nil; [failedURLs release], failedURLs = nil; [super dealloc]; @@ -72,32 +74,34 @@ static SDWebImageManager *instance; } // Check the on-disk cache async so we don't block the main thread + [cacheDelegates addObject:delegate]; NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:delegate, @"delegate", url, @"url", [NSNumber numberWithBool:lowPriority], @"low_priority", nil]; [[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString] delegate:self userInfo:info]; } - (void)cancelForDelegate:(id)delegate { - NSUInteger idx = [delegates indexOfObjectIdenticalTo:delegate]; + // Remove all instances of delegate from cacheDelegates. + // (removeObjectIdenticalTo: does this, despite its singular name.) + [cacheDelegates removeObjectIdenticalTo:delegate]; - if (idx == NSNotFound) + NSUInteger idx; + while ((idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]) != NSNotFound) { - return; + SDWebImageDownloader *downloader = [[downloaders objectAtIndex:idx] retain]; + + [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]; + } + + [downloader release]; } - - SDWebImageDownloader *downloader = [[downloaders objectAtIndex:idx] retain]; - - [delegates 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]; - } - - [downloader release]; } #pragma mark SDImageCacheDelegate @@ -105,10 +109,23 @@ static SDWebImageManager *instance; - (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forKey:(NSString *)key userInfo:(NSDictionary *)info { id delegate = [info objectForKey:@"delegate"]; + + NSUInteger idx = [cacheDelegates indexOfObjectIdenticalTo:delegate]; + if (idx == NSNotFound) + { + // Request has since been canceled + return; + } + if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]) { [delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image]; } + + // Remove one instance of delegate from the array, + // not all of them (as |removeObjectIdenticalTo:| would) + // in case multiple requests are issued. + [cacheDelegates removeObjectAtIndex:idx]; } - (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info @@ -117,6 +134,15 @@ static SDWebImageManager *instance; id delegate = [info objectForKey:@"delegate"]; BOOL lowPriority = [[info objectForKey:@"low_priority"] boolValue]; + NSUInteger idx = [cacheDelegates indexOfObjectIdenticalTo:delegate]; + if (idx == NSNotFound) + { + // Request has since been canceled + return; + } + + [cacheDelegates removeObjectAtIndex:idx]; + // Share the same downloader for identical URLs so we don't download the same URL several times SDWebImageDownloader *downloader = [downloaderForURL objectForKey:url]; @@ -132,7 +158,7 @@ static SDWebImageManager *instance; downloader.lowPriority = NO; } - [delegates addObject:delegate]; + [downloadDelegates addObject:delegate]; [downloaders addObject:downloader]; } @@ -142,14 +168,14 @@ static SDWebImageManager *instance; { [downloader retain]; - // Notify all the delegates with this 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) { - id delegate = [delegates objectAtIndex:uidx]; + id delegate = [downloadDelegates objectAtIndex:uidx]; if (image) { @@ -167,7 +193,7 @@ static SDWebImageManager *instance; } [downloaders removeObjectAtIndex:uidx]; - [delegates removeObjectAtIndex:uidx]; + [downloadDelegates removeObjectAtIndex:uidx]; } } @@ -195,14 +221,14 @@ static SDWebImageManager *instance; { [downloader retain]; - // Notify all the delegates with this 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) { - id delegate = [delegates objectAtIndex:uidx]; + id delegate = [downloadDelegates objectAtIndex:uidx]; if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]) { @@ -210,7 +236,7 @@ static SDWebImageManager *instance; } [downloaders removeObjectAtIndex:uidx]; - [delegates removeObjectAtIndex:uidx]; + [downloadDelegates removeObjectAtIndex:uidx]; } }