Skip to content

Instantly share code, notes, and snippets.

@arashkashi
Forked from Sorix/AsynchronousOperation.swift
Last active September 26, 2019 09:01
Show Gist options
  • Save arashkashi/2f901f83bf1020995ca67e130e560ca4 to your computer and use it in GitHub Desktop.
Save arashkashi/2f901f83bf1020995ca67e130e560ca4 to your computer and use it in GitHub Desktop.
Subclass of NSOperation to make it asynchronous in Swift 3
//
// AsynchronousOperation.swift
//
// Created by Vasily Ulianov on 09.02.17.
// Copyright © 2017 Vasily Ulianov. All rights reserved.
//
import Foundation
/// Subclass of `Operation` that add support of asynchronous operations.
/// ## How to use:
/// 1. Call `super.main()` when override `main` method, call `super.start()` when override `start` method.
/// 2. When operation is finished or cancelled set `self.state = .finished`
class AsyncOperation: Operation {
override var isAsynchronous: Bool { return true }
override var isExecuting: Bool { return state == .executing }
override var isFinished: Bool { return state == .finished }
var state = State.ready {
willSet {
willChangeValue(forKey: state.keyPath)
willChangeValue(forKey: newValue.keyPath)
}
didSet {
didChangeValue(forKey: state.keyPath)
didChangeValue(forKey: oldValue.keyPath)
}
}
enum State: String {
case ready = "Ready"
case executing = "Executing"
case finished = "Finished"
case canceled = "isCancelled"
fileprivate var keyPath: String { return "is" + self.rawValue }
}
override func start() {
if self.isCancelled {
state = .finished
} else {
state = .ready
main()
}
}
override func main() {
if self.isCancelled {
state = .finished
} else {
state = .executing
}
}
}
class TestOperation: AsyncOperation {
var delay: Int
init(delay: Int) {
self.delay = delay
}
override func main() {
if self.isCancelled {
state = .finished
} else {
state = .executing
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(self.delay), execute: {
print("delay: \(self.delay)")
self.state = .finished
})
}
}
}
// if cancel op2 right after adding them to the queue the currect implementation would
// execute op3 (since it has less delay) first and then op1 . but if we bring the cancel
// into logic then only op1 exedcutes.
let op1 = TestOperation(delay: 3000)
let op2 = TestOperation(delay: 2000)
let op3 = TestOperation(delay: 1000)
op1.completionBlock = { print("op1 finished") }
let queue = OperationQueue()
let operations = [op1, op2, op3]
for i in stride(from: operations.count - 1, to: 0, by: -1) {
print("\(i) depends on \(i-1)")
operations[i].addDependency(operations[i-1])
}
queue.addOperations(operations, waitUntilFinished: false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment