summaryrefslogtreecommitdiffhomepage
path: root/ios/Operations
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2023-04-14 14:37:53 +0200
committerAndrej Mihajlov <and@mullvad.net>2023-04-14 14:37:53 +0200
commit9ed9e881a1e16f4ec4b3783970e84a0023a6dbbc (patch)
treee0a4fa0962ad28141a3fe18bb53eb155d3f2543c /ios/Operations
parent09ca3b13667b4ea6562d5520aa47913d8b60ceb2 (diff)
parent5d9a79e7706cb09fb6612419d2ad5a8243924a16 (diff)
downloadmullvadvpn-9ed9e881a1e16f4ec4b3783970e84a0023a6dbbc.tar.xz
mullvadvpn-9ed9e881a1e16f4ec4b3783970e84a0023a6dbbc.zip
Merge branch 'operation-cancellation-ios-105'
Diffstat (limited to 'ios/Operations')
-rw-r--r--ios/Operations/AsyncBlockOperation.swift2
-rw-r--r--ios/Operations/AsyncOperation.swift43
-rw-r--r--ios/Operations/AsyncOperationQueue.swift6
-rw-r--r--ios/Operations/NoFailedDependenciesCondition.swift8
-rw-r--r--ios/Operations/ResultBlockOperation.swift2
-rw-r--r--ios/Operations/TransformOperation.swift2
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)