Skip to content

Instantly share code, notes, and snippets.

@CodaFi
Last active November 3, 2021 05:08
Show Gist options
  • Save CodaFi/c323a7b8a50e1fba34c21230eb5aead4 to your computer and use it in GitHub Desktop.
Save CodaFi/c323a7b8a50e1fba34c21230eb5aead4 to your computer and use it in GitHub Desktop.
class AsyncOperation: Operation {
private(set) var taskHandle: Task.Handle<Void, Error>?
fileprivate enum State: Equatable {
case ready
case executing
case finished
}
fileprivate var state: State = .ready {
willSet {
willChangeValue(forKey: "state")
}
didSet {
didChangeValue(forKey: "state")
}
}
/// To be overridden by subclasses to perform their work
func perform() async throws {
fatalError("perform() must be overridden in subclass \(type(of: self))")
}
/// Main entry point, not to be overridden by subclasses
override func start() {
guard !self.isCancelled else {
return
}
self.state = .executing
self.taskHandle = async {
do {
try Task.checkCancellation()
_ = try await self.perform()
} catch {}
self.state = .finished
self.taskHandle = nil
}
}
override func cancel() {
super.cancel()
self.taskHandle?.cancel()
self.taskHandle = nil
self.state = .finished
}
override var isAsynchronous: Bool {
return true
}
override var isReady: Bool {
return super.isReady && self.state == .ready
}
override var isExecuting: Bool {
return self.state == .executing
}
override var isFinished: Bool {
return self.state == .finished
}
@objc class func keyPathsForValuesAffectingIsReady() -> Set<String> {
return ["state"]
}
@objc class func keyPathsForValuesAffectingIsExecuting() -> Set<String> {
return ["state"]
}
@objc class func keyPathsForValuesAffectingIsFinished() -> Set<String> {
return ["state"]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment