Skip to content

Instantly share code, notes, and snippets.

@NSSimpleApps
Last active December 23, 2023 19:09
Show Gist options
  • Save NSSimpleApps/b95ce2046a5df36e6015e613f22f1355 to your computer and use it in GitHub Desktop.
Save NSSimpleApps/b95ce2046a5df36e6015e613f22f1355 to your computer and use it in GitHub Desktop.
AppercodeAsyncOperation
/// Асинхронная операция. Завершать методом finish(with:).
final class AppercodeAsyncOperation<T>: Operation {
enum State: Int {
case ready
case executing
case finished
case cancelled
}
private let lock = NSLock()
private var state = State.ready
private var result: Result<T, Error>?
private let block: (AppercodeAsyncOperation) -> Void
init(block: @escaping (AppercodeAsyncOperation) -> Void, completion: @escaping (Result<T, Error>?) -> Void) {
self.block = block
super.init()
self.completionBlock = { [unowned self] in
self.lock.lock()
let result = self.result
self.lock.unlock()
completion(result)
}
}
override var isAsynchronous: Bool {
return true
}
override var isCancelled: Bool {
self.lock.lock()
let isCancelled = self.state == .cancelled
self.lock.unlock()
return isCancelled
}
override func cancel() {
self.lock.lock()
let state = self.state
self.lock.unlock()
if state == .executing || state == .ready {
self.willChangeValue(forKey: "isReady")
self.willChangeValue(forKey: "isCancelled")
self.willChangeValue(forKey: "isExecuting")
self.willChangeValue(forKey: "isFinished")
self.lock.lock()
self.result = nil
self.state = .cancelled
self.lock.unlock()
self.didChangeValue(forKey: "isReady")
self.didChangeValue(forKey: "isCancelled")
self.didChangeValue(forKey: "isExecuting")
self.didChangeValue(forKey: "isFinished")
}
}
override var isExecuting: Bool {
self.lock.lock()
let isExecuting = self.state == .executing
self.lock.unlock()
return isExecuting
}
override var isFinished: Bool {
self.lock.lock()
let state = self.state
let isFinished = state == .finished || state == .cancelled
self.lock.unlock()
return isFinished
}
override var isReady: Bool {
self.lock.lock()
let isReady = self.state == .ready
self.lock.unlock()
return isReady
}
override func start() {
self.lock.lock()
let state = self.state
self.lock.unlock()
if state == .ready {
self.willChangeValue(forKey: "isReady")
self.willChangeValue(forKey: "isExecuting")
self.lock.lock()
self.state = .executing
self.lock.unlock()
self.didChangeValue(forKey: "isReady")
self.didChangeValue(forKey: "isExecuting")
self.main()
}
}
override func main() {
self.block(self)
}
func finish(with result: Result<T, Error>) {
self.lock.lock()
let state = self.state
self.lock.unlock()
if state == .executing || state == .ready {
self.willChangeValue(forKey: "isReady")
self.willChangeValue(forKey: "isExecuting")
self.willChangeValue(forKey: "isFinished")
self.lock.lock()
self.result = result
self.state = .finished
self.lock.unlock()
self.didChangeValue(forKey: "isReady")
self.didChangeValue(forKey: "isExecuting")
self.didChangeValue(forKey: "isFinished")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment