Skip to content

Instantly share code, notes, and snippets.

@voxels
Forked from calebd/AsynchronousOperation.swift
Created January 15, 2017 21:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voxels/8a4289c9208c156528c702e7e93f29cd to your computer and use it in GitHub Desktop.
Save voxels/8a4289c9208c156528c702e7e93f29cd to your computer and use it in GitHub Desktop.
Concurrent NSOperation in Swift
import Foundation
/// An abstract class that makes building simple asynchronous operations easy.
/// Subclasses must implement `execute()` to perform any work and call
/// `finish()` when they are done. All `NSOperation` work will be handled
/// automatically.
open class Operation: Foundation.Operation {
// MARK: - Properties
private let stateQueue = DispatchQueue(
label: "com.calebd.operation.state",
attributes: .concurrent)
private var rawState = OperationState.ready
@objc private dynamic var state: OperationState {
get {
return stateQueue.sync(execute: { rawState })
}
set {
willChangeValue(forKey: "state")
stateQueue.sync(
flags: .barrier,
execute: { rawState = newValue })
didChangeValue(forKey: "state")
}
}
public final override var isReady: Bool {
return state == .ready && super.isReady
}
public final override var isExecuting: Bool {
return state == .executing
}
public final override var isFinished: Bool {
return state == .finished
}
// MARK: - NSObject
@objc private dynamic class func keyPathsForValuesAffectingIsReady() -> Set<String> {
return ["state"]
}
@objc private dynamic class func keyPathsForValuesAffectingIsExecuting() -> Set<String> {
return ["state"]
}
@objc private dynamic class func keyPathsForValuesAffectingIsFinished() -> Set<String> {
return ["state"]
}
// MARK: - Foundation.Operation
public override final func start() {
super.start()
if isCancelled {
finish()
return
}
state = .executing
execute()
}
// MARK: - Public
/// Subclasses must implement this to perform their work and they must not
/// call `super`. The default implementation of this function throws an
/// exception.
open func execute() {
fatalError("Subclasses must implement `execute`.")
}
/// Call this function after any work is done or after a call to `cancel()`
/// to move the operation into a completed state.
public final func finish() {
state = .finished
}
}
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment