diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2023-04-14 14:37:53 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2023-04-14 14:37:53 +0200 |
| commit | 9ed9e881a1e16f4ec4b3783970e84a0023a6dbbc (patch) | |
| tree | e0a4fa0962ad28141a3fe18bb53eb155d3f2543c /ios/Operations | |
| parent | 09ca3b13667b4ea6562d5520aa47913d8b60ceb2 (diff) | |
| parent | 5d9a79e7706cb09fb6612419d2ad5a8243924a16 (diff) | |
| download | mullvadvpn-9ed9e881a1e16f4ec4b3783970e84a0023a6dbbc.tar.xz mullvadvpn-9ed9e881a1e16f4ec4b3783970e84a0023a6dbbc.zip | |
Merge branch 'operation-cancellation-ios-105'
Diffstat (limited to 'ios/Operations')
| -rw-r--r-- | ios/Operations/AsyncBlockOperation.swift | 2 | ||||
| -rw-r--r-- | ios/Operations/AsyncOperation.swift | 43 | ||||
| -rw-r--r-- | ios/Operations/AsyncOperationQueue.swift | 6 | ||||
| -rw-r--r-- | ios/Operations/NoFailedDependenciesCondition.swift | 8 | ||||
| -rw-r--r-- | ios/Operations/ResultBlockOperation.swift | 2 | ||||
| -rw-r--r-- | ios/Operations/TransformOperation.swift | 2 |
6 files changed, 40 insertions, 23 deletions
diff --git a/ios/Operations/AsyncBlockOperation.swift b/ios/Operations/AsyncBlockOperation.swift index e23b138d53..43be9b8275 100644 --- a/ios/Operations/AsyncBlockOperation.swift +++ b/ios/Operations/AsyncBlockOperation.swift @@ -74,7 +74,7 @@ public class AsyncBlockOperation: AsyncOperation { public func addCancellationBlock(_ block: @escaping () -> Void) { dispatchQueue.async { - if self.isCancelled { + if self.isCancelled, self.isExecuting { block() } else { self.cancellationBlocks.append(block) diff --git a/ios/Operations/AsyncOperation.swift b/ios/Operations/AsyncOperation.swift index 2939f0708e..2ca049030c 100644 --- a/ios/Operations/AsyncOperation.swift +++ b/ios/Operations/AsyncOperation.swift @@ -307,8 +307,9 @@ open class AsyncOperation: Operation { private func _start() { operationLock.lock() if _isCancelled { + notifyCancellation() operationLock.unlock() - finish() + finish(error: OperationError.cancelled) } else { state = .executing @@ -326,26 +327,21 @@ open class AsyncOperation: Operation { } override public final func cancel() { - var notifyDidCancel = false - operationLock.lock() if !_isCancelled { _isCancelled = true - notifyDidCancel = true - } - operationLock.unlock() - - super.cancel() - if notifyDidCancel { - dispatchQueue.async { - self.operationDidCancel() - - for observer in self.observers { - observer.operationDidCancel(self) + // Notify observers only when executing, otherwise `_start()` will take care of doing this as soon + // as operation is ready to execute. + if state == .executing { + dispatchQueue.async { + self.notifyCancellation() } } } + operationLock.unlock() + + super.cancel() } public func finish() { @@ -399,6 +395,14 @@ open class AsyncOperation: Operation { return true } + private func notifyCancellation() { + operationDidCancel() + + for observer in _observers { + observer.operationDidCancel(self) + } + } + // MARK: - Subclass overrides open func operationDidCancel() { @@ -422,6 +426,17 @@ public protocol OperationBlockObserverSupport {} extension AsyncOperation: OperationBlockObserverSupport {} extension OperationBlockObserverSupport where Self: AsyncOperation { + /// Add observer responding to cancellation event. + public func onCancel(_ fn: @escaping (Self) -> Void) { + addBlockObserver(OperationBlockObserver(didCancel: fn)) + } + + /// Add observer responding to finish event. + public func onFinish(_ fn: @escaping (Self, Error?) -> Void) { + addBlockObserver(OperationBlockObserver(didFinish: fn)) + } + + /// Add block-based observer. public func addBlockObserver(_ observer: OperationBlockObserver<Self>) { addObserver(observer) } diff --git a/ios/Operations/AsyncOperationQueue.swift b/ios/Operations/AsyncOperationQueue.swift index 4579546084..d1269a8175 100644 --- a/ios/Operations/AsyncOperationQueue.swift +++ b/ios/Operations/AsyncOperationQueue.swift @@ -73,11 +73,9 @@ private final class ExclusivityManager { operationsByCategory[category] = operations - let blockObserver = OperationBlockObserver(didFinish: { [weak self] op, error in + operation.onFinish { [weak self] op, error in self?.removeOperation(op, categories: categories) - }) - - operation.addObserver(blockObserver) + } } } diff --git a/ios/Operations/NoFailedDependenciesCondition.swift b/ios/Operations/NoFailedDependenciesCondition.swift index 2e96a12593..81523e511d 100644 --- a/ios/Operations/NoFailedDependenciesCondition.swift +++ b/ios/Operations/NoFailedDependenciesCondition.swift @@ -24,11 +24,15 @@ public final class NoFailedDependenciesCondition: OperationCondition { public func evaluate(for operation: Operation, completion: @escaping (Bool) -> Void) { let satisfy = operation.dependencies.allSatisfy { operation in - if let operation = operation as? AsyncOperation, operation.error != nil { + let operationError = (operation as? AsyncOperation)?.error + let isCancellationError = operationError?.isOperationCancellationError ?? false + + if operationError != nil, !isCancellationError { return false } - if operation.isCancelled, !self.ignoreCancellations { + // Treat OperationError.cancelled and isCancelled equally. + if operation.isCancelled || isCancellationError, !self.ignoreCancellations { return false } diff --git a/ios/Operations/ResultBlockOperation.swift b/ios/Operations/ResultBlockOperation.swift index 5f21cd202e..5d848b438d 100644 --- a/ios/Operations/ResultBlockOperation.swift +++ b/ios/Operations/ResultBlockOperation.swift @@ -88,7 +88,7 @@ public final class ResultBlockOperation<Success>: ResultOperation<Success> { public func addCancellationBlock(_ block: @escaping () -> Void) { dispatchQueue.async { - if self.isCancelled { + if self.isCancelled, self.isExecuting { block() } else { self.cancellationBlocks.append(block) diff --git a/ios/Operations/TransformOperation.swift b/ios/Operations/TransformOperation.swift index 0b144707be..609e07896c 100644 --- a/ios/Operations/TransformOperation.swift +++ b/ios/Operations/TransformOperation.swift @@ -102,7 +102,7 @@ public final class TransformOperation<Input, Output>: ResultOperation<Output>, I public func addCancellationBlock(_ block: @escaping () -> Void) { dispatchQueue.async { - if self.isCancelled { + if self.isCancelled, self.isExecuting { block() } else { self.cancellationBlocks.append(block) |
