我已经对Operation
进行了子类化以支持异步操作。
名为 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)
}
并且应用程序崩溃,因为操作已经以某种方式分派(dispatch)到队列,当我检查断点时,我创建的 state
属性是 Ready
并且 原始操作的 isExecuting
字段为 true
。发生的情况是我的 state
属性和操作状态字段未同步。如果我检查不同实现中的 state
字段,它确实会进入 Executing
和 Finished
我如何确保它们始终同步? p>
最佳答案
您应该使用 NSLock 来保护对 state
属性的读取和写入。
看一下 session 的示例代码 Advanced NSOperation摘自 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")
}
}
关于ios - 操作状态不是线程安全的 Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44850188/