Replacing #781 - made sure all the completionBlocks called from `SDWebImageDownloaderOperation` are called on the main queue. Created 2 methods to simplify the code for calling the completions

This commit is contained in:
Bogdan Poplauschi 2016-09-30 14:43:38 +03:00
parent f7e8246014
commit c77adf449a
1 changed files with 29 additions and 29 deletions

View File

@ -102,7 +102,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy]; callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy];
[callbacks removeObjectIdenticalTo:[NSNull null]]; [callbacks removeObjectIdenticalTo:[NSNull null]];
}); });
return callbacks; return [callbacks copy]; // strip mutability here
} }
- (BOOL)cancel:(nullable id)token { - (BOOL)cancel:(nullable id)token {
@ -175,9 +175,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];
}); });
} else { } else {
for (SDWebImageDownloaderCompletedBlock completedBlock in [self callbacksForKey:kCompletedCallbackKey]) { [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}]];
completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES);
}
} }
#if SD_UIKIT #if SD_UIKIT
@ -286,10 +284,9 @@ didReceiveResponse:(NSURLResponse *)response
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
}); });
[self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:((NSHTTPURLResponse *)response).statusCode userInfo:nil]];
for (SDWebImageDownloaderCompletedBlock completedBlock in [self callbacksForKey:kCompletedCallbackKey]) {
completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:((NSHTTPURLResponse *)response).statusCode userInfo:nil], YES);
}
[self done]; [self done];
} }
@ -372,11 +369,8 @@ didReceiveResponse:(NSURLResponse *)response
image = scaledImage; image = scaledImage;
} }
CGImageRelease(partialImageRef); CGImageRelease(partialImageRef);
dispatch_main_async_safe(^{
for (SDWebImageDownloaderCompletedBlock completedBlock in [self callbacksForKey:kCompletedCallbackKey]) { [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO];
completedBlock(image, nil, nil, NO);
}
});
} }
} }
@ -408,7 +402,6 @@ didReceiveResponse:(NSURLResponse *)response
#pragma mark NSURLSessionTaskDelegate #pragma mark NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSArray<id> *completionBlocks = [[self callbacksForKey:kCompletedCallbackKey] copy];
@synchronized(self) { @synchronized(self) {
self.dataTask = nil; self.dataTask = nil;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
@ -420,11 +413,9 @@ didReceiveResponse:(NSURLResponse *)response
} }
if (error) { if (error) {
for (SDWebImageDownloaderCompletedBlock completionBlock in completionBlocks) { [self callCompletionBlocksWithError:error];
completionBlock(nil, nil, error, YES);
}
} else { } else {
if (completionBlocks.count > 0) { if ([self callbacksForKey:kCompletedCallbackKey].count > 0) {
/** /**
* See #1608 and #1623 - apparently, there is a race condition on `NSURLCache` that causes a crash * See #1608 and #1623 - apparently, there is a race condition on `NSURLCache` that causes a crash
* Limited the calls to `cachedResponseForRequest:` only for cases where we should ignore the cached response * Limited the calls to `cachedResponseForRequest:` only for cases where we should ignore the cached response
@ -432,9 +423,8 @@ didReceiveResponse:(NSURLResponse *)response
* Note: responseFromCached is set to NO inside `willCacheResponse:`. This method doesn't get called for large images or images behind authentication * Note: responseFromCached is set to NO inside `willCacheResponse:`. This method doesn't get called for large images or images behind authentication
*/ */
if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached && [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request]) { if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached && [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request]) {
for (SDWebImageDownloaderCompletedBlock completionBlock in completionBlocks) { // hack
completionBlock(nil, nil, nil, YES); [self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES];
}
} else if (self.imageData) { } else if (self.imageData) {
UIImage *image = [UIImage sd_imageWithData:self.imageData]; UIImage *image = [UIImage sd_imageWithData:self.imageData];
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
@ -447,18 +437,12 @@ didReceiveResponse:(NSURLResponse *)response
} }
} }
if (CGSizeEqualToSize(image.size, CGSizeZero)) { if (CGSizeEqualToSize(image.size, CGSizeZero)) {
for (SDWebImageDownloaderCompletedBlock completionBlock in completionBlocks) { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]];
completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES);
}
} else { } else {
for (SDWebImageDownloaderCompletedBlock completionBlock in completionBlocks) { [self callCompletionBlocksWithImage:image imageData:self.imageData error:nil finished:YES];
completionBlock(image, self.imageData, nil, YES);
}
} }
} else { } else {
for (SDWebImageDownloaderCompletedBlock completionBlock in completionBlocks) { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]];
completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}], YES);
}
} }
} }
} }
@ -530,4 +514,20 @@ didReceiveResponse:(NSURLResponse *)response
return self.options & SDWebImageDownloaderContinueInBackground; return self.options & SDWebImageDownloaderContinueInBackground;
} }
- (void)callCompletionBlocksWithError:(nullable NSError *)error {
[self callCompletionBlocksWithImage:nil imageData:nil error:error finished:YES];
}
- (void)callCompletionBlocksWithImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
error:(nullable NSError *)error
finished:(BOOL)finished {
NSArray<id> *completionBlocks = [self callbacksForKey:kCompletedCallbackKey];
dispatch_main_async_safe(^{
for (SDWebImageDownloaderCompletedBlock completedBlock in completionBlocks) {
completedBlock(image, imageData, error, finished);
}
});
}
@end @end