diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-03-23 14:42:08 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-03-31 14:39:43 +0200 |
| commit | d71995c950f87e0866862bc2c6191d2e2e59deb8 (patch) | |
| tree | 4c741062a0cacf05a62ce36c77bc66d81ed55f52 /ios/MullvadVPN | |
| parent | a0735ca20791a33b4f0ac613f3488959cf07c93a (diff) | |
| download | mullvadvpn-d71995c950f87e0866862bc2c6191d2e2e59deb8.tar.xz mullvadvpn-d71995c950f87e0866862bc2c6191d2e2e59deb8.zip | |
Add ResultOperation
Diffstat (limited to 'ios/MullvadVPN')
| -rw-r--r-- | ios/MullvadVPN/Operations/ResultOperation.swift | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/ios/MullvadVPN/Operations/ResultOperation.swift b/ios/MullvadVPN/Operations/ResultOperation.swift new file mode 100644 index 0000000000..ba2cd59c4e --- /dev/null +++ b/ios/MullvadVPN/Operations/ResultOperation.swift @@ -0,0 +1,77 @@ +// +// ResultOperation.swift +// MullvadVPN +// +// Created by pronebird on 23/03/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +/// Base class for operations producing result. +class ResultOperation<Success, Failure: Error>: AsyncOperation { + typealias Completion = OperationCompletion<Success, Failure> + typealias CompletionHandler = (Completion) -> Void + + private let stateLock = NSLock() + private var completionValue: Completion? + private let completionQueue: DispatchQueue? + private var completionHandler: CompletionHandler? + + var completion: Completion? { + stateLock.lock() + defer { stateLock.unlock() } + return completionValue + } + + init(completionQueue: DispatchQueue?, completionHandler: CompletionHandler?) { + self.completionQueue = completionQueue + self.completionHandler = completionHandler + + super.init() + } + + 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.") + } + } + + func finish(completion: Completion) { + stateLock.lock() + + // Bail if operation is already finishing. + guard completionValue == nil else { + stateLock.unlock() + return + } + + // Store completion value. + completionValue = completion + + // Copy completion handler. + let completionHandler: CompletionHandler? = self.completionHandler + + // Unset completion handler. + self.completionHandler = nil + + stateLock.unlock() + + let block = { + // Call completion handler. + completionHandler?(completion) + + // Finish operation. + super.finish() + } + + if let completionQueue = completionQueue { + completionQueue.async(execute: block) + } else { + block() + } + } +} |
