我已经将Operation
子类化,以支持异步操作。
新类名为AsyncOperation
,并添加了名为state
的新字段
这是一个enum
来帮助管理运营状态。
class AsyncOperation: Operation {
// DONE: State enum with keyPath property
enum State: String {
case Ready, Executing, Finished
fileprivate var keyPath: String {
return "is" + rawValue
}
}
// DONE: state property
var state = State.Ready {
willSet {
willChangeValue(forKey: newValue.keyPath)
willChangeValue(forKey: state.keyPath)
}
didSet {
didChangeValue(forKey: oldValue.keyPath)
didChangeValue(forKey: state.keyPath)
}
}
}
extension AsyncOperation {
// DONE: Operation Overrides
override var isReady: Bool {
return super.isReady && state == .Ready
}
override var isExecuting: Bool {
return state == .Executing
}
override var isFinished: Bool {
return state == .Finished
}
override var isAsynchronous: Bool {
return true
}
override func start() {
if isCancelled {
state = .Finished
return
}
main()
state = .Executing
}
override func cancel() {
state = .Finished
}
}
一般来说,这个子类运行得很好,我很满意它。 我经历了一些奇怪的行为...... 在某些情况下,我将一个操作添加到队列中,如下所示:
//this code happens in mainViewController
//op is an operation that belong to mainViewController and could dispatched to the queue from many places, its init called once in view did load.
op = SomeAsyncOperation()
if(op.state == .Executing){
queue.addOperatiom(op)
}
并且应用程序崩溃,因为操作以某种方式已经调度到队列,当我使用断点检查我创建的state
属性是Ready
和原始的isExecuting
字段操作是true
。发生的是我的state
属性,并且未同步操作状态字段。如果我检查不同实现中的state
字段,它会转到Executing
和Finished
如何确定这些字段始终会同步?
答案 0 :(得分:1)
您应该使用NSLock来保护对state
属性的读写操作。
从WWDC 2015
查看会话Advanced NSOperation的示例代码重要的部分是:
/// Private storage for the `state` property that will be KVO observed.
private var _state = State.Initialized
/// A lock to guard reads and writes to the `_state` property
private let stateLock = NSLock()
private var state: State {
get {
return stateLock.withCriticalScope {
_state
}
}
set(newState) {
/*
It's important to note that the KVO notifications are NOT called from inside
the lock. If they were, the app would deadlock, because in the middle of
calling the `didChangeValueForKey()` method, the observers try to access
properties like "isReady" or "isFinished". Since those methods also
acquire the lock, then we'd be stuck waiting on our own lock. It's the
classic definition of deadlock.
*/
willChangeValueForKey("state")
stateLock.withCriticalScope { Void -> Void in
guard _state != .Finished else {
return
}
assert(_state.canTransitionToState(newState), "Performing invalid state transition.")
_state = newState
}
didChangeValueForKey("state")
}
}