Ios 操作状态不是线程安全的
我将Ios 操作状态不是线程安全的,ios,swift,multithreading,nsoperation,nsoperationqueue,Ios,Swift,Multithreading,Nsoperation,Nsoperationqueue,我将操作子类化,以支持异步操作。 新类名为AsyncOperation,并添加了名为state 这是一个枚举,用于帮助管理操作状态 class AsyncOperation: Operation { // DONE: State enum with keyPath property enum State: String { case Ready, Executing, Finished fileprivate var keyPath: String { return "is" + r
操作
子类化,以支持异步操作。
新类名为AsyncOperation
,并添加了名为state
这是一个枚举
,用于帮助管理操作状态
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)
}
而应用程序崩溃是因为操作以某种方式已经调度到队列,当我用断点检查时,我创建的
状态
属性是就绪
,原始操作的isExecuting
字段是真
。发生的是我的状态
属性,操作状态字段未同步。如果我在不同的实现中检查状态
字段,它确实会进入执行
和完成
如何确保它们始终同步?您应该使用NSLock来保护对状态
属性的读写
查看WWDC 2015会议的示例代码
重要的部分是:
/// 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")
}
}