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
This commit is contained in:
parent
7f966ae69c
commit
0c2c9965f0
|
@ -181,6 +181,18 @@ static SDWebImageManager *instance;
|
|||
}
|
||||
#endif
|
||||
|
||||
- (void)removeObjectsForDelegate:(id<SDWebImageManagerDelegate>)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<SDWebImageManagerDelegate>)delegate
|
||||
{
|
||||
NSUInteger idx;
|
||||
|
@ -276,9 +288,14 @@ static SDWebImageManager *instance;
|
|||
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 @@ static SDWebImageManager *instance;
|
|||
|
||||
- (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<SDWebImageManagerDelegate> delegate = [downloadDelegates objectAtIndex:uidx];
|
||||
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i];
|
||||
if (aDownloader != downloader) {
|
||||
continue;
|
||||
}
|
||||
|
||||
id<SDWebImageManagerDelegate> 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 @@ static SDWebImageManager *instance;
|
|||
}
|
||||
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 @@ static SDWebImageManager *instance;
|
|||
{
|
||||
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<SDWebImageManagerDelegate> 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<SDWebImageManagerDelegate> delegate = [downloadDelegates objectAtIndex:i];
|
||||
SDWIRetain(delegate);
|
||||
SDWIAutorelease(delegate);
|
||||
NSDictionary *info = [downloadInfo objectAtIndex:i];
|
||||
SDWIRetain(info);
|
||||
SDWIAutorelease(info);
|
||||
|
||||
if (image)
|
||||
{
|
||||
|
@ -382,7 +426,7 @@ static SDWebImageManager *instance;
|
|||
}
|
||||
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 @@ static SDWebImageManager *instance;
|
|||
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 @@ static SDWebImageManager *instance;
|
|||
}
|
||||
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 @@ static SDWebImageManager *instance;
|
|||
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 @@ static SDWebImageManager *instance;
|
|||
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<SDWebImageManagerDelegate> delegate = [downloadDelegates objectAtIndex:uidx];
|
||||
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:i];
|
||||
if (aDownloader != downloader) {
|
||||
continue;
|
||||
}
|
||||
id<SDWebImageManagerDelegate> 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 @@ static SDWebImageManager *instance;
|
|||
}
|
||||
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 @@ static SDWebImageManager *instance;
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue