Fix the rare case that we setFinished=YES before NSOperation started. This may cause exception from Foundation

This commit is contained in:
DreamPiggy 2020-12-28 17:39:17 +08:00
parent f5fd53b2d2
commit 5ce33b12ba
1 changed files with 10 additions and 7 deletions

View File

@ -144,7 +144,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
- (void)start { - (void)start {
@synchronized (self) { @synchronized (self) {
if (self.isCancelled) { if (self.isCancelled) {
self.finished = YES; if (!self.isFinished) self.finished = YES;
// Operation cancelled by user before sending the request // Operation cancelled by user before sending the request
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCancelled userInfo:@{NSLocalizedDescriptionKey : @"Operation cancelled by user before sending the request"}]]; [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCancelled userInfo:@{NSLocalizedDescriptionKey : @"Operation cancelled by user before sending the request"}]];
[self reset]; [self reset];
@ -218,8 +218,9 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:strongSelf]; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:strongSelf];
}); });
} else { } else {
if (!self.isFinished) self.finished = YES;
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]]; [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]];
[self done]; [self reset];
} }
} }
@ -237,11 +238,6 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:strongSelf]; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:strongSelf];
}); });
// As we cancelled the task, its callback won't be called and thus won't
// maintain the isFinished and isExecuting flags.
if (self.isExecuting) self.executing = NO;
if (!self.isFinished) self.finished = YES;
if (self.dataTask) { if (self.dataTask) {
// Cancel the URLSession, `URLSession:task:didCompleteWithError:` delegate callback will be ignored // Cancel the URLSession, `URLSession:task:didCompleteWithError:` delegate callback will be ignored
@ -249,6 +245,13 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
self.dataTask = nil; self.dataTask = nil;
} }
// NSOperation disallow setFinished=YES **before** operation's start method been called
// We check for the initialized status and only setFinished=YES for running status.
if (self.isExecuting || self.isFinished) {
if (self.isExecuting) self.executing = NO;
if (!self.isFinished) self.finished = YES;
}
// Operation cancelled by user during sending the request // Operation cancelled by user during sending the request
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCancelled userInfo:@{NSLocalizedDescriptionKey : @"Operation cancelled by user during sending the request"}]]; [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCancelled userInfo:@{NSLocalizedDescriptionKey : @"Operation cancelled by user during sending the request"}]];