summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-06-08 14:48:02 +0200
committerAndrej Mihajlov <and@mullvad.net>2022-06-08 15:43:49 +0200
commit6499f8a92996aa1d035180637d1592fdf13ad513 (patch)
tree67039c3e5460c2975e01b1af043433dd84e8eec8
parent3227e1999eb540fd8645cd0f4c8e370851714662 (diff)
downloadmullvadvpn-6499f8a92996aa1d035180637d1592fdf13ad513.tar.xz
mullvadvpn-6499f8a92996aa1d035180637d1592fdf13ad513.zip
Observe individual dependencies
-rw-r--r--ios/MullvadVPN/Operations/AsyncOperation.swift80
1 files changed, 38 insertions, 42 deletions
diff --git a/ios/MullvadVPN/Operations/AsyncOperation.swift b/ios/MullvadVPN/Operations/AsyncOperation.swift
index d3e13d2f81..6815311fab 100644
--- a/ios/MullvadVPN/Operations/AsyncOperation.swift
+++ b/ios/MullvadVPN/Operations/AsyncOperation.swift
@@ -40,9 +40,7 @@ import Foundation
/// A base implementation of an asynchronous operation
class AsyncOperation: Operation {
- private static var observerContext = 0
-
- /// A state lock used for manipulating the operation state flags in a thread safe fashion.
+ /// A state lock used for manipulating the operation state in a thread safe fashion.
private let stateLock = NSRecursiveLock()
/// Operation state.
@@ -181,21 +179,6 @@ class AsyncOperation: Operation {
init(dispatchQueue: DispatchQueue? = nil) {
self.dispatchQueue = dispatchQueue ?? DispatchQueue(label: "AsyncOperation.dispatchQueue")
super.init()
-
- addObserver(
- self,
- forKeyPath: #keyPath(isReady),
- options: [],
- context: &Self.observerContext
- )
- }
-
- deinit {
- removeObserver(
- self,
- forKeyPath: #keyPath(isReady),
- context: &Self.observerContext
- )
}
// MARK: - KVO
@@ -212,25 +195,6 @@ class AsyncOperation: Operation {
return ["state"]
}
- override func observeValue(
- forKeyPath keyPath: String?,
- of object: Any?,
- change: [NSKeyValueChangeKey : Any]?,
- context: UnsafeMutableRawPointer?
- )
- {
- if context == &Self.observerContext {
- checkReadiness()
- } else {
- super.observeValue(
- forKeyPath: keyPath,
- of: object,
- change: change,
- context: context
- )
- }
- }
-
// MARK: - Lifecycle
final override func start() {
@@ -323,16 +287,48 @@ class AsyncOperation: Operation {
didChangeValue(for: \.state)
}
- private func checkReadiness() {
+ private func dependenciesDidFinish() {
stateLock.lock()
- if state == .pending && !_isCancelled && super.isReady {
- evaluateConditions()
- }
- stateLock.unlock()
+ defer { stateLock.unlock() }
+
+ guard state == .pending && !_isCancelled else { return }
+
+ precondition(super.isReady, "Expect super.isReady to be true.")
+
+ evaluateConditions()
}
func didEnqueue() {
+ stateLock.lock()
+ guard state == .initialized else {
+ stateLock.unlock()
+ return
+ }
setState(.pending)
+ stateLock.unlock()
+
+ let group = DispatchGroup()
+ var observers = [NSKeyValueObservation]()
+
+ for dependency in dependencies {
+ group.enter()
+
+ let observer = dependency.observe(\.isFinished, options: [.initial]) { dependency, _ in
+ if dependency.isFinished {
+ group.leave()
+ }
+ }
+
+ observers.append(observer)
+ }
+
+ group.notify(queue: dispatchQueue) {
+ for observer in observers {
+ observer.invalidate()
+ }
+
+ self.dependenciesDidFinish()
+ }
}
// MARK: - Subclass overrides