Swift 试图理解异步操作子类
我正试图开始在一个辅助项目中使用Swift 试图理解异步操作子类,swift,nsoperation,Swift,Nsoperation,我正试图开始在一个辅助项目中使用操作s,而不是在我的网络代码中到处都是基于闭包的回调,以帮助消除嵌套调用。所以我读了一些关于这个主题的书,我遇到了实现: 开放类异步操作:操作{ //标记:-属性 private let stateQueue=DispatchQueue(标签:“asynchronous.operation.state”,属性:。并发) private var rawState=OperationState.ready 私有动态var状态:OperationState{ 得到{ r
操作
s,而不是在我的网络代码中到处都是基于闭包的回调,以帮助消除嵌套调用。所以我读了一些关于这个主题的书,我遇到了实现:
开放类异步操作:操作{
//标记:-属性
private let stateQueue=DispatchQueue(标签:“asynchronous.operation.state”,属性:。并发)
private var rawState=OperationState.ready
私有动态var状态:OperationState{
得到{
return stateQueue.sync(执行:{
原始状态
})
}
设置{
willChangeValue(forKey:“州”)
stateQueue.sync(标志:。屏障,执行:{
rawState=newValue
})
didChangeValue(forKey:“状态”)
}
}
公共最终覆盖变量已就绪:Bool{
返回状态==.ready&&super.isReady
}
公共最终覆盖变量正在执行:Bool{
返回状态==。正在执行
}
公共最终覆盖变量isFinished:Bool{
返回状态==.finished
}
公共最终覆盖:Bool{
返回真值
}
//标记:-NSObject
私有动态类func KEYPATHSFORVALUESFECTINGISREADY()->Set{
返回[“状态”]
}
私有动态类func keypathsforvaluesafectingisexecuting()->Set{
返回[“状态”]
}
私有动态类func keypathsforvaluesafectingisfinished()->Set{
返回[“状态”]
}
//标记:基础操作
公共最终覆盖函数开始(){
super.start()
如果取消{
完成()
返回
}
状态=.executing
执行()
}
//马克:公众
///子类必须实现此功能才能执行其工作,并且不能调用“super”。此函数的默认实现会引发异常。
open func execute(){
fatalError(“子类必须实现'execute`.”)
}
///在完成任何工作或调用“cancel()”后调用此函数,以将操作移动到完成状态。
公共最终功能完成(){
状态=.finished
}
}
@objc私有枚举操作状态:Int{
案例准备
案件执行
案件审理完毕
}
这个操作
子类有一些实现细节,我想在理解时得到一些帮助
stateQueue
属性的用途是什么?我看到state
computed属性的get
和set
正在使用它,但是我找不到任何文档来解释它们使用的sync:flags:execute
和sync:execute
方法NSObject
部分中返回[“state”]
的三个类方法的用途是什么?我看不到它们在任何地方被使用。我在NSObject
中找到了类func-keypathsforvaluesafectingvalue(forKey:String)->Set
,但这似乎不能帮助我理解为什么要声明这些方法关于您的第一个问题:stateQueue在向您写入新值时锁定您的操作操作状态,方法是:
return stateQueue.sync(execute: {
rawState
})
及
由于您的操作是异步的,所以在读取或写入一个状态之前,可以调用另一个状态。就像你想写iExecution,但同时我已经完成了调用。因此,为了避免这种情况,stateQueue锁定要读写的操作状态,直到它完成上一次调用。它像原子弹一样工作。相反,使用调度队列,您可以使用NSLock的扩展来简化执行WWDC 2015中高级NSOperations示例代码中的关键代码,并且您可以实现如下功能:
private let stateLock = NSLock()
private dynamic var state: OperationState {
get {
return stateLock.withCriticalScope{ rawState }
}
set {
willChangeValue(forKey: "state")
stateLock.withCriticalScope {
rawState = newValue
}
didChangeValue(forKey: "state")
}
}
关于第二个问题:只读属性isReady、isExecuting、isFinished的KVO通知用于管理操作状态。您可以阅读以下内容:为了更好地理解KVO,请将文章张贴到最后 你说:
stateQueue
属性的用途是什么?我看到它被state
computed属性的get和set使用,但我找不到任何文档来解释它们使用的sync:flags:execute
和sync:execute
方法NSOperation
子类化时,必须确保任何重写的方法都可以安全地从多个线程调用。如果在子类中实现自定义方法,例如自定义数据访问器,则还必须确保这些方法是线程安全的。因此,必须同步对操作中任何数据变量的访问,以防止潜在的数据损坏。有关同步的详细信息,请参阅
关于同步的并发队列的确切使用,这被称为“读写器”模式。读写器模式的这一基本概念是,读取可以相互并发(因此sync
,没有障碍),但写入不能与该属性的任何其他访问并发(因此async
,有障碍)
例如,您可以在如下阵列上实现线程安全读写器:
class ThreadSafeArray<T> {
private var values: [T]
private let queue = DispatchQueue(label: "...", attributes: .concurrent)
init(_ values: [T]) {
self.values = values
}
func reader<U>(block: () throws -> U) rethrows -> U {
return try queue.sync {
try block()
}
}
func writer(block: @escaping (inout [T]) -> Void) {
queue.async(flags: .barrier) {
block(&self.values)
}
}
// e.g. you might use `reader` and `writer` like the following:
subscript(_ index: Int) -> T {
get { reader { values[index] } }
set { writer { $0[index] = newValue } }
}
func append(_ value: T) {
writer { $0.append(value) }
}
func remove(at index: Int) {
writer { $0.remove(at: index)}
}
}
使用中更新的代码段时,应注意此更改可能导致的错误:
class ThreadSafeArray<T> {
private var values: [T]
private let queue = DispatchQueue(label: "...", attributes: .concurrent)
init(_ values: [T]) {
self.values = values
}
func reader<U>(block: () throws -> U) rethrows -> U {
return try queue.sync {
try block()
}
}
func writer(block: @escaping (inout [T]) -> Void) {
queue.async(flags: .barrier) {
block(&self.values)
}
}
// e.g. you might use `reader` and `writer` like the following:
subscript(_ index: Int) -> T {
get { reader { values[index] } }
set { writer { $0[index] = newValue } }
}
func append(_ value: T) {
writer { $0.append(value) }
}
func remove(at index: Int) {
writer { $0.remove(at: index)}
}
}
public class AsynchronousOperation: Operation {
/// State for this operation.
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
/// Concurrent queue for synchronizing access to `state`.
private let stateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".rw.state", attributes: .concurrent)
/// Private backing stored property for `state`.
private var _state: OperationState = .ready
/// The state of the operation
@objc private dynamic var state: OperationState {
get { return stateQueue.sync { _state } }
set { stateQueue.async(flags: .barrier) { self._state = newValue } }
}
// MARK: - Various `Operation` properties
open 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 }
public final override var isAsynchronous: Bool { return true }
// KVN for dependent properties
open override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
if ["isReady", "isFinished", "isExecuting"].contains(key) {
return [#keyPath(state)]
}
return super.keyPathsForValuesAffectingValue(forKey: key)
}
// Start
public final override func start() {
if isCancelled {
state = .finished
return
}
state = .executing
main()
}
/// Subclasses must implement this to perform their work and they must not call `super`. The default implementation of this function throws an exception.
open override func main() {
fatalError("Subclasses must implement `main`.")
}
/// Call this function to finish an operation that is currently executing
public final func finish() {
if !isFinished { state = .finished }
}
}