diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2021-09-14 13:59:01 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2021-09-15 10:54:31 +0200 |
| commit | 76dd2c99bf92d608022efbf05ffcbfebda43e0c1 (patch) | |
| tree | 8cccb074a033089ac531e425f4a825df62b616c3 /ios/MullvadVPN/Operations | |
| parent | e553d10b869c46e7ab922b86c32f4bd016e4fdac (diff) | |
| download | mullvadvpn-76dd2c99bf92d608022efbf05ffcbfebda43e0c1.tar.xz mullvadvpn-76dd2c99bf92d608022efbf05ffcbfebda43e0c1.zip | |
Operations: simplify AsyncOperation, remove advanced features
Diffstat (limited to 'ios/MullvadVPN/Operations')
| -rw-r--r-- | ios/MullvadVPN/Operations/AnyOperationObserver.swift | 19 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/AssociatedValue.swift | 31 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/AsyncBlockOperation.swift | 5 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/AsyncOperation.swift | 122 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/DelayOperation.swift | 48 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/InputOperation.swift | 103 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/OperationBlockObserver.swift | 67 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/OperationObserver.swift | 18 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/OperationProtocol.swift | 20 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/OutputOperation.swift | 50 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/ResultOperation.swift | 63 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/RetryOperation.swift | 120 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/TransformOperation.swift | 50 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/TransformOperationObserver.swift | 45 |
14 files changed, 27 insertions, 734 deletions
diff --git a/ios/MullvadVPN/Operations/AnyOperationObserver.swift b/ios/MullvadVPN/Operations/AnyOperationObserver.swift deleted file mode 100644 index 9c394f8b5a..0000000000 --- a/ios/MullvadVPN/Operations/AnyOperationObserver.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// AnyOperationObserver.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -class AnyOperationObserver<OperationType: OperationProtocol>: OperationBlockObserver<OperationType> { - init<T: OperationObserver>(_ observer: T) where T.OperationType == OperationType { - super.init( - willExecute: observer.operationWillExecute, - willFinish: observer.operationWillFinish, - didFinish: observer.operationDidFinish - ) - } -} diff --git a/ios/MullvadVPN/Operations/AssociatedValue.swift b/ios/MullvadVPN/Operations/AssociatedValue.swift deleted file mode 100644 index 6fc860dbf3..0000000000 --- a/ios/MullvadVPN/Operations/AssociatedValue.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// AssociatedValue.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -/// A container type for storing associated values -final class AssociatedValue<T>: NSObject { - let value: T - init(_ value: T) { - self.value = value - } - - class func get(object: Any, key: UnsafeRawPointer) -> T? { - let container = objc_getAssociatedObject(object, key) as? AssociatedValue<T> - return container?.value - } - - class func set(object: Any, key: UnsafeRawPointer, value: T?) { - objc_setAssociatedObject( - object, - key, - value.flatMap { AssociatedValue($0) }, - .OBJC_ASSOCIATION_RETAIN_NONATOMIC - ) - } -} diff --git a/ios/MullvadVPN/Operations/AsyncBlockOperation.swift b/ios/MullvadVPN/Operations/AsyncBlockOperation.swift index c8f4287b32..a7f0ffdd29 100644 --- a/ios/MullvadVPN/Operations/AsyncBlockOperation.swift +++ b/ios/MullvadVPN/Operations/AsyncBlockOperation.swift @@ -10,7 +10,7 @@ import Foundation /// Asynchronous block operation class AsyncBlockOperation: AsyncOperation { - private let block: (@escaping () -> Void) -> Void + private let block: ((@escaping () -> Void) -> Void) init(_ block: @escaping (@escaping () -> Void) -> Void) { self.block = block @@ -18,9 +18,8 @@ class AsyncBlockOperation: AsyncOperation { } override func main() { - self.block { [weak self] in + block { [weak self] in self?.finish() } } } - diff --git a/ios/MullvadVPN/Operations/AsyncOperation.swift b/ios/MullvadVPN/Operations/AsyncOperation.swift index 44e8e791f3..2d1819ee30 100644 --- a/ios/MullvadVPN/Operations/AsyncOperation.swift +++ b/ios/MullvadVPN/Operations/AsyncOperation.swift @@ -9,17 +9,10 @@ import Foundation /// A base implementation of an asynchronous operation -class AsyncOperation: Operation, OperationProtocol { - - /// A state transaction lock used to perform critical sections of code within `start`, `cancel` - /// and `finish` calls. - fileprivate let transactionLock = NSRecursiveLock() +class AsyncOperation: Operation { /// A state lock used for manipulating the operation state flags in a thread safe fashion. - fileprivate let stateLock = NSRecursiveLock() - - /// The operation observers. - fileprivate var observers: [AnyOperationObserver<AsyncOperation>] = [] + private let stateLock = NSRecursiveLock() /// Operation state flags. private var _isExecuting = false @@ -43,14 +36,14 @@ class AsyncOperation: Operation, OperationProtocol { } final override func start() { - transactionLock.withCriticalBlock { - if self.isCancelled { - self.finish() - } else { - self.observers.forEach { $0.operationWillExecute(self) } - self.setExecuting(true) - self.main() - } + stateLock.lock() + if _isCancelled { + finish() + stateLock.unlock() + } else { + setExecuting(true) + stateLock.unlock() + main() } } @@ -58,99 +51,34 @@ class AsyncOperation: Operation, OperationProtocol { // Override in subclasses } - /// Cancel operation - /// Subclasses should override `operationDidCancel` instead - final override func cancel() { - transactionLock.withCriticalBlock { - if self.isCancelled { - super.cancel() - } else { - self.setCancelled(true) - - super.cancel() - - // Only notify the operation about cancellation when it is already running, - // otherwise the call to `start` should automatically `finish()` the operation. - if self.isExecuting { - self.operationDidCancel() - } + override func cancel() { + stateLock.withCriticalBlock { + if !_isCancelled { + willChangeValue(for: \.isCancelled) + _isCancelled = true + didChangeValue(for: \.isCancelled) } } - } - - /// Override in subclasses to support task cancellation. - /// Subclasses should call `finish()` to complete the operation - func operationDidCancel() { - // no-op + super.cancel() } final func finish() { - transactionLock.withCriticalBlock { - guard !self.isFinished else { return } - - self.stateLock.withCriticalBlock { - self.observers.forEach { $0.operationWillFinish(self) } - } - - if self.isExecuting { - self.setExecuting(false) + stateLock.withCriticalBlock { + if _isExecuting { + setExecuting(false) } - self.setFinished(true) - - self.stateLock.withCriticalBlock { - self.observers.forEach { $0.operationDidFinish(self) } + if !_isFinished { + willChangeValue(for: \.isFinished) + _isFinished = true + didChangeValue(for: \.isFinished) } } } private func setExecuting(_ value: Bool) { willChangeValue(for: \.isExecuting) - stateLock.withCriticalBlock { _isExecuting = value } + _isExecuting = value didChangeValue(for: \.isExecuting) } - - private func setFinished(_ value: Bool) { - willChangeValue(for: \.isFinished) - stateLock.withCriticalBlock { _isFinished = value } - didChangeValue(for: \.isFinished) - } - - private func setCancelled(_ value: Bool) { - willChangeValue(for: \.isCancelled) - stateLock.withCriticalBlock { _isCancelled = value } - didChangeValue(for: \.isCancelled) - } - - // MARK: - Observation - - /// Add type-erased operation observer - fileprivate func addAnyObserver(_ observer: AnyOperationObserver<AsyncOperation>) { - stateLock.withCriticalBlock { - self.observers.append(observer) - } - } -} - -/// This extension exists because Swift has some issues with infering the associated type in `OperationObserver` -extension OperationProtocol where Self: AsyncOperation { - func addObserver<T: OperationObserver>(_ observer: T) where T.OperationType == Self { - let transform = TransformOperationObserver<AsyncOperation>(observer) - let wrapped = AnyOperationObserver(transform) - addAnyObserver(wrapped) - } -} - - -protocol OperationSubclassing { - /// Use this method in subclasses or extensions where you would like to synchronize - /// the class members access using the same lock used for guarding from race conditions - /// when managing operation state. - func synchronized<T>(_ body: () -> T) -> T -} - -extension AsyncOperation: OperationSubclassing { - func synchronized<T>(_ body: () -> T) -> T { - return stateLock.withCriticalBlock(body) - } } diff --git a/ios/MullvadVPN/Operations/DelayOperation.swift b/ios/MullvadVPN/Operations/DelayOperation.swift deleted file mode 100644 index 80719b573d..0000000000 --- a/ios/MullvadVPN/Operations/DelayOperation.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// DelayOperation.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -enum DelayTimerType { - case deadline - case walltime -} - -class DelayOperation: AsyncOperation { - private let delay: TimeInterval - private let timerType: DelayTimerType - private var timer: DispatchSourceTimer? - - init(delay: TimeInterval, timerType: DelayTimerType) { - self.delay = delay - self.timerType = timerType - } - - override func main() { - let timer = DispatchSource.makeTimerSource() - timer.setEventHandler { [weak self] in - self?.finish() - } - - switch timerType { - case .deadline: - timer.schedule(deadline: DispatchTime.now() + delay) - case .walltime: - timer.schedule(wallDeadline: DispatchWallTime.now() + delay) - } - - self.timer = timer - timer.activate() - } - - override func operationDidCancel() { - timer?.cancel() - timer = nil - finish() - } -} diff --git a/ios/MullvadVPN/Operations/InputOperation.swift b/ios/MullvadVPN/Operations/InputOperation.swift deleted file mode 100644 index a1c9d6931d..0000000000 --- a/ios/MullvadVPN/Operations/InputOperation.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// InputOperation.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -protocol InputOperation: OperationProtocol { - associatedtype Input - - /// When overriding `input` in Subclasses, make sure to call `operationDidSetInput` - var input: Input? { get set } - - func operationDidSetInput(_ input: Input?) -} - -private var kInputOperationAssociatedValue = 0 -extension InputOperation where Self: OperationSubclassing { - var input: Input? { - get { - return synchronized { - return AssociatedValue.get(object: self, key: &kInputOperationAssociatedValue) - } - } - set { - synchronized { - AssociatedValue.set(object: self, key: &kInputOperationAssociatedValue, value: newValue) - - operationDidSetInput(newValue) - } - } - } - - func operationDidSetInput(_ input: Input?) { - // Override in subclasses - } -} - -extension InputOperation { - - @discardableResult func inject<Dependency>(from dependency: Dependency, via block: @escaping (Dependency.Output) -> Input?) -> Self - where Dependency: OutputOperation - { - let observer = OperationBlockObserver<Dependency>(willFinish: { [weak self] (operation) in - guard let self = self else { return } - - if let output = operation.output { - self.input = block(output) - } - }) - dependency.addObserver(observer) - addDependency(dependency) - - return self - } - - @discardableResult func injectResult<Dependency>(from dependency: Dependency) -> Self - where Dependency: OutputOperation, Dependency.Output == Input? - { - return self.inject(from: dependency, via: { $0 }) - } - - /// Inject input from operation that outputs `Result<Input, Failure>` - @discardableResult func injectResult<Dependency, Failure>(from dependency: Dependency) -> Self - where Dependency: OutputOperation, Failure: Error, Dependency.Output == Result<Input, Failure> - { - return self.inject(from: dependency) { (output) -> Input? in - switch output { - case .success(let value): - return value - case .failure: - return nil - } - } - } - - /// Inject input from operation that outputs `Result<Input, Never>` - @discardableResult func injectResult<Dependency>(from dependency: Dependency) -> Self - where Dependency: OutputOperation, Dependency.Output == Result<Input, Never> - { - return self.inject(from: dependency) { (output) -> Input? in - switch output { - case .success(let value): - return value - } - } - } - - /// Inject input from operation that outputs `Result<Input?, Never>` - @discardableResult func injectResult<Dependency>(from dependency: Dependency) -> Self - where Dependency: OutputOperation, Dependency.Output == Result<Input?, Never> - { - return self.inject(from: dependency) { (output) -> Input? in - switch output { - case .success(let value): - return value - } - } - } -} diff --git a/ios/MullvadVPN/Operations/OperationBlockObserver.swift b/ios/MullvadVPN/Operations/OperationBlockObserver.swift deleted file mode 100644 index 1ba2f1ae50..0000000000 --- a/ios/MullvadVPN/Operations/OperationBlockObserver.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// OperationBlockObserver.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -class OperationBlockObserver<OperationType: OperationProtocol>: OperationObserver { - private var willExecute: ((OperationType) -> Void)? - private var willFinish: ((OperationType) -> Void)? - private var didFinish: ((OperationType) -> Void)? - - let queue: DispatchQueue? - - init( - queue: DispatchQueue? = nil, - willExecute: ((OperationType) -> Void)? = nil, - willFinish: ((OperationType) -> Void)? = nil, - didFinish: ((OperationType) -> Void)? = nil - ) { - self.queue = queue - self.willExecute = willExecute - self.willFinish = willFinish - self.didFinish = didFinish - } - - func operationWillExecute(_ operation: OperationType) { - if let willExecute = willExecute { - scheduleEvent { - willExecute(operation) - } - } - } - - func operationWillFinish(_ operation: OperationType) { - if let willFinish = self.willFinish { - scheduleEvent { - willFinish(operation) - } - } - } - - func operationDidFinish(_ operation: OperationType) { - if let didFinish = self.didFinish { - scheduleEvent { - didFinish(operation) - } - } - } - - private func scheduleEvent(_ body: @escaping () -> Void) { - if let queue = queue { - queue.async(execute: body) - } else { - body() - } - } -} - -extension OperationProtocol { - func addDidFinishBlockObserver(queue: DispatchQueue? = nil, _ block: @escaping (Self) -> Void) { - addObserver(OperationBlockObserver(queue: queue, didFinish: block)) - } -} diff --git a/ios/MullvadVPN/Operations/OperationObserver.swift b/ios/MullvadVPN/Operations/OperationObserver.swift deleted file mode 100644 index a7d3ea3aa3..0000000000 --- a/ios/MullvadVPN/Operations/OperationObserver.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// OperationObserver.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -protocol OperationObserver { - associatedtype OperationType: OperationProtocol - - func operationWillExecute(_ operation: OperationType) - func operationWillFinish(_ operation: OperationType) - func operationDidFinish(_ operation: OperationType) -} - diff --git a/ios/MullvadVPN/Operations/OperationProtocol.swift b/ios/MullvadVPN/Operations/OperationProtocol.swift deleted file mode 100644 index a41102c265..0000000000 --- a/ios/MullvadVPN/Operations/OperationProtocol.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// OperationProtocol.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -protocol OperationProtocol: Operation { - /// Add operation observer - func addObserver<T: OperationObserver>(_ observer: T) where T.OperationType == Self - - /// Finish operation - func finish() - - /// Cancel operation - func cancel() -} diff --git a/ios/MullvadVPN/Operations/OutputOperation.swift b/ios/MullvadVPN/Operations/OutputOperation.swift deleted file mode 100644 index 064d54a2e9..0000000000 --- a/ios/MullvadVPN/Operations/OutputOperation.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// OutputOperation.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -protocol OutputOperation: OperationProtocol { - associatedtype Output - - var output: Output? { get set } - - func finish(with output: Output) -} - -extension OutputOperation { - func finish(with output: Output) { - self.output = output - self.finish() - } -} - -private var kOutputOperationAssociatedValue = 0 -extension OutputOperation where Self: OperationSubclassing { - var output: Output? { - get { - return synchronized { - return AssociatedValue.get(object: self, key: &kOutputOperationAssociatedValue) - } - } - set { - synchronized { - AssociatedValue.set(object: self, key: &kOutputOperationAssociatedValue, value: newValue) - } - } - } -} - -extension OperationProtocol where Self: OutputOperation { - func addDidFinishBlockObserver(queue: DispatchQueue? = nil, _ block: @escaping (Self, Output) -> Void) { - addDidFinishBlockObserver(queue: queue) { (operation) in - if let output = operation.output { - block(operation, output) - } - } - } -} diff --git a/ios/MullvadVPN/Operations/ResultOperation.swift b/ios/MullvadVPN/Operations/ResultOperation.swift deleted file mode 100644 index 7ce9c20358..0000000000 --- a/ios/MullvadVPN/Operations/ResultOperation.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// ResultOperation.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -class ResultOperation<Success, Failure: Error>: AsyncOperation, OutputOperation { - typealias Output = Result<Success, Failure> - - private enum Executor { - case callback((@escaping (Result<Success, Failure>) -> Void) -> Void) - case transform(() -> Result<Success, Failure>) - } - - private let executor: Executor - - private init(_ executor: Executor) { - self.executor = executor - } - - convenience init(_ block: @escaping (@escaping (Output) -> Void) -> Void) { - self.init(.callback(block)) - } - - convenience init(_ block: @escaping () -> Output) { - self.init(.transform(block)) - } - - override func main() { - switch executor { - case .callback(let block): - block { [weak self] (result) in - self?.finish(with: result) - } - - case .transform(let block): - self.finish(with: block()) - } - } - -} - -extension ResultOperation where Failure == Never { - /// A convenience initializer for infallible `ResultOperation` that automatically wraps the - /// return value of the given closure into `Result<Success, Never>` - convenience init(_ block: @escaping () -> Success) { - self.init(.transform({ .success(block()) })) - } - - /// A convenience initializer for infallible `ResultOperation` that automatically wraps the - /// value, passed to the given closure, into `Result<Success, Never>` - convenience init(_ block: @escaping (@escaping (Success) -> Void) -> Void) { - self.init(.callback({ (finish) in - block { - finish(.success($0)) - } - })) - } -} diff --git a/ios/MullvadVPN/Operations/RetryOperation.swift b/ios/MullvadVPN/Operations/RetryOperation.swift deleted file mode 100644 index 1e73e81d79..0000000000 --- a/ios/MullvadVPN/Operations/RetryOperation.swift +++ /dev/null @@ -1,120 +0,0 @@ -// -// RetryOperation.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -enum WaitStrategy { - case immediate - case constant(TimeInterval) - - var iterator: AnyIterator<TimeInterval> { - switch self { - case .immediate: - return AnyIterator { .zero } - case .constant(let constant): - return AnyIterator { constant } - } - } -} - -struct RetryStrategy { - var maxRetries: Int - var waitStrategy: WaitStrategy - var waitTimerType: DelayTimerType -} - -class RetryOperation<OperationType, Success, Failure: Error>: AsyncOperation, OutputOperation - where OperationType: OutputOperation, OperationType.Output == Result<Success, Failure> -{ - typealias Output = OperationType.Output - - private let operationQueue = OperationQueue() - - private let producer: () -> OperationType - private let delayIterator: AnyIterator<TimeInterval> - - private var retryCount: Int = 0 - private let retryStrategy: RetryStrategy - - private var childConfigurator: ((OperationType) -> Void)? - - init(underlyingQueue: DispatchQueue? = nil, strategy: RetryStrategy, producer: @escaping () -> OperationType) { - operationQueue.underlyingQueue = underlyingQueue - delayIterator = strategy.waitStrategy.iterator - retryStrategy = strategy - self.producer = producer - } - - override func main() { - retry() - } - - override func operationDidCancel() { - operationQueue.cancelAllOperations() - } - - private func retry(delay: TimeInterval? = nil) { - let child = producer() - - child.addDidFinishBlockObserver { [weak self] (operation) in - guard let self = self else { return } - - // Operation finished without output set? - guard let result = operation.output else { - self.finish() - return - } - - self.synchronized { - guard case .failure(let error) = result, - let delay = self.delayIterator.next(), - self.shouldRetry(error: error) else { - self.finish(with: result) - return - } - - self.retryCount += 1 - self.retry(delay: delay) - } - } - - synchronized { - childConfigurator?(child) - } - - if let delay = delay { - let delayOperation = DelayOperation(delay: delay, timerType: retryStrategy.waitTimerType) - - child.addDependency(delayOperation) - operationQueue.addOperation(delayOperation) - } - - operationQueue.addOperation(child) - } - - private func setChildConfigurator(_ body: @escaping (OperationType) -> Void) { - synchronized { - self.childConfigurator = body - } - } - - private func shouldRetry(error: Failure) -> Bool { - return retryCount < retryStrategy.maxRetries && !self.isCancelled - } - -} - -extension RetryOperation: InputOperation where OperationType: InputOperation { - typealias Input = OperationType.Input - - func operationDidSetInput(_ input: OperationType.Input?) { - setChildConfigurator { (child) in - child.input = input - } - } -} diff --git a/ios/MullvadVPN/Operations/TransformOperation.swift b/ios/MullvadVPN/Operations/TransformOperation.swift deleted file mode 100644 index ce2a1617ea..0000000000 --- a/ios/MullvadVPN/Operations/TransformOperation.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// TransformOperation.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -class TransformOperation<Input, Output>: AsyncOperation, InputOperation, OutputOperation { - private enum Executor { - case callback((Input, @escaping (Output) -> Void) -> Void) - case transform((Input) -> Output) - } - - private let executor: Executor - - private init(input: Input? = nil, executor: Executor) { - self.executor = executor - - super.init() - self.input = input - } - - convenience init(input: Input? = nil, _ block: @escaping (Input, @escaping (Output) -> Void) -> Void) { - self.init(input: input, executor: .callback(block)) - } - - convenience init(input: Input? = nil, _ block: @escaping (Input) -> Output) { - self.init(input: input, executor: .transform(block)) - } - - override func main() { - guard let input = input else { - self.finish() - return - } - - switch executor { - case .callback(let block): - block(input) { [weak self] (result) in - self?.finish(with: result) - } - - case .transform(let block): - self.finish(with: block(input)) - } - } -} diff --git a/ios/MullvadVPN/Operations/TransformOperationObserver.swift b/ios/MullvadVPN/Operations/TransformOperationObserver.swift deleted file mode 100644 index e6ed695e0b..0000000000 --- a/ios/MullvadVPN/Operations/TransformOperationObserver.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// TransformOperationObserver.swift -// MullvadVPN -// -// Created by pronebird on 06/07/2020. -// Copyright © 2020 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -/// A private type erasing observer that type casts the input operation type to the expected -/// operation type before calling the wrapped observer -class TransformOperationObserver<S: OperationProtocol>: OperationObserver { - private let willExecute: (S) -> Void - private let willFinish: (S) -> Void - private let didFinish: (S) -> Void - - init<T: OperationObserver>(_ observer: T) { - willExecute = Self.wrap(observer.operationWillExecute) - willFinish = Self.wrap(observer.operationWillFinish) - didFinish = Self.wrap(observer.operationDidFinish) - } - - func operationWillExecute(_ operation: S) { - willExecute(operation) - } - - func operationWillFinish(_ operation: S) { - willFinish(operation) - } - - func operationDidFinish(_ operation: S) { - didFinish(operation) - } - - private class func wrap<U>(_ body: @escaping (U) -> Void) -> (S) -> Void { - return { (operation: S) in - if let transformed = operation as? U { - body(transformed) - } else { - fatalError("\(Self.self) failed to cast \(S.self) to \(U.self)") - } - } - } -} |
