Merge pull request #3146 from dreampiggy/fix_potential_cancel_before_start

Fix the case that we setFinished=YES before NSOperation started. This may cause exception from Foundation
This commit is contained in:
DreamPiggy 2020-12-29 11:38:45 +08:00 committed by GitHub
commit 52dd3a11ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 11 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];
}
}
@ -237,11 +238,6 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
dispatch_async(dispatch_get_main_queue(), ^{
[[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
@ -249,6 +245,14 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
self.dataTask = nil;
}
// NSOperation disallow setFinished=YES **before** operation's start method been called
// We check for the initialized status, which is isExecuting == NO && isFinished = NO
// Ony update for non-intialized status, which is !(isExecuting == NO && isFinished = NO), or if (self.isExecuting || self.isFinished) {...}
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"}]];