In chapter 8, we modify AsyncOperation
to contain states using enum. Property observers for this property looks as follows:
var state = State.ready {
willSet {
willChangeValue(forKey: newValue.keyPath)
willChangeValue(forKey: state.keyPath)
}
didSet {
didChangeValue(forKey: oldValue.keyPath)
didChangeValue(forKey: state.keyPath)
}
}
But, no where here we are taking care of thread-safety. Documentation of Operation
class ask us to take care of thread-safety while overriding required properties. If we scan through internet, we find various implementations of asynchronous operation subclass which take care of thread-safety using custom DispatchQueue
. One of the closest implementation looks as follows (original source) :
open class AsynchronousOperation: Operation {
public override var isAsynchronous: Bool {
return true
}
public override var isExecuting: Bool {
return state == .executing
}
public override var isFinished: Bool {
return state == .finished
}
public override func start() {
if self.isCancelled {
state = .finished
} else {
state = .ready
main()
}
}
open override func main() {
if self.isCancelled {
state = .finished
} else {
state = .executing
}
}
public func finish() {
state = .finished
}
// MARK: - State management
public enum State: String {
case ready = "Ready"
case executing = "Executing"
case finished = "Finished"
fileprivate var keyPath: String { return "is" + self.rawValue }
}
/// Thread-safe computed state value
public var state: State {
get {
stateQueue.sync {
return stateStore
}
}
set {
let oldValue = state
willChangeValue(forKey: state.keyPath)
willChangeValue(forKey: newValue.keyPath)
stateQueue.sync(flags: .barrier) {
stateStore = newValue
}
didChangeValue(forKey: state.keyPath)
didChangeValue(forKey: oldValue.keyPath)
}
}
private let stateQueue = DispatchQueue(label: "AsynchronousOperation State Queue", attributes: .concurrent)
/// Non thread-safe state storage, use only with locks
private var stateStore: State = .ready
}
My question is, why are we not taking care of thread-safety in the example mentioned in our book? Is there something that I am missing? Or, is thread-safety automatically inferred due to some code in our example?