diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-04-16 15:09:20 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-04-29 10:30:25 +0200 |
| commit | f658aa645b816f31a98590638899a86467f2a8b7 (patch) | |
| tree | 513e872b33d63a082afb0edde10ebdccefb437df | |
| parent | d3b82886935ab2ccdda355057b096248b7a6f301 (diff) | |
| download | mullvadvpn-f658aa645b816f31a98590638899a86467f2a8b7.tar.xz mullvadvpn-f658aa645b816f31a98590638899a86467f2a8b7.zip | |
ResultOperation: refactor how finish() is handled to avoid preconditionFailure
| -rw-r--r-- | ios/MullvadVPN/Operations/ResultOperation.swift | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/ios/MullvadVPN/Operations/ResultOperation.swift b/ios/MullvadVPN/Operations/ResultOperation.swift index 3d9233ce2e..a0cab6dcc9 100644 --- a/ios/MullvadVPN/Operations/ResultOperation.swift +++ b/ios/MullvadVPN/Operations/ResultOperation.swift @@ -17,6 +17,7 @@ class ResultOperation<Success, Failure: Error>: AsyncOperation { private var completionValue: Completion? private let completionQueue: DispatchQueue? private var completionHandler: CompletionHandler? + private var pendingFinish = false var completion: Completion? { stateLock.lock() @@ -33,32 +34,38 @@ class ResultOperation<Success, Failure: Error>: AsyncOperation { @available(*, unavailable) override func finish() { - // Propagate cancellation if finish() is called directly from start(). - if isCancelled { - finish(completion: .cancelled) - } else { - preconditionFailure("Use finish(completion:) to finish operation.") - } + _finish() } func finish(completion: Completion) { stateLock.lock() + if completionValue == nil { + completionValue = completion + } + stateLock.unlock() + _finish() + } + + private func _finish() { + stateLock.lock() // Bail if operation is already finishing. - guard completionValue == nil else { + guard !pendingFinish else { stateLock.unlock() return } - // Store completion value. - completionValue = completion + // Mark that operation is pending finish. + pendingFinish = true // Copy completion handler. - let completionHandler: CompletionHandler? = self.completionHandler + let completionHandler = self.completionHandler // Unset completion handler. self.completionHandler = nil + // Copy completion value. + let completion = completionValue ?? .cancelled stateLock.unlock() let block = { |
