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 {
@synchronized (self) {
if (self.isCancelled) {
self.finished = YES;
if (!self.isFinished) self.finished = YES;
// 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];
@ -218,8 +218,9 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:strongSelf];
});
} else {
if (!self.isFinished) self.finished = YES;
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]];
[self done];
[self reset];
}
}
@ -238,17 +239,19 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
[[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) {
// Cancel the URLSession, `URLSession:task:didCompleteWithError:` delegate callback will be ignored
[self.dataTask cancel];
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
[self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCancelled userInfo:@{NSLocalizedDescriptionKey : @"Operation cancelled by user during sending the request"}]];