Skip to content

Instantly share code, notes, and snippets.

@smosko
Created March 7, 2019 09:37
Show Gist options
  • Save smosko/50fb46e35507b2e876f9dd38926fa0f7 to your computer and use it in GitHub Desktop.
Save smosko/50fb46e35507b2e876f9dd38926fa0f7 to your computer and use it in GitHub Desktop.
AsyncOperation
import Foundation
open class AsyncOperation: Operation {
private enum State: String {
case ready = "isReady"
case executing = "isExecuting"
case finished = "isFinished"
}
private var _state = Atomic(State.ready)
private let queue = DispatchQueue(label: "AsyncOperation.state")
private var state: State {
get {
return _state.value
}
set {
queue.sync {
let oldValue = _state.value
guard newValue != oldValue else { return }
willChangeValue(forKey: newValue.rawValue)
willChangeValue(forKey: oldValue.rawValue)
_state.mutate { $0 = newValue }
didChangeValue(forKey: oldValue.rawValue)
didChangeValue(forKey: newValue.rawValue)
}
}
}
final override public var isReady: Bool {
return state == .ready && super.isReady
}
final override public var isExecuting: Bool {
return state == .executing
}
final override public var isFinished: Bool {
return state == .finished
}
final override public var isAsynchronous: Bool {
return true
}
final override public func start() {
if isCancelled {
state = .finished
} else {
main()
}
}
final override public func main() {
if isCancelled {
state = .finished
} else {
state = .executing
execute()
}
}
// override this method in subclass to do actual async work and call finish() in completion handler
open func execute() {
finish()
}
final public func finish() {
if isExecuting {
state = .finished
}
}
}