Nic*_*hrn 20 nsoperation swift
我试图开始Operation
在侧面项目中使用s而不是在我的网络代码中散布基于闭包的回调以帮助消除嵌套调用.所以我正在做一些关于这个主题的阅读,我遇到了这个实现:
open class AsynchronousOperation: Operation {
// MARK: - Properties
private let stateQueue = DispatchQueue(label: "asynchronous.operation.state", attributes: .concurrent)
private var rawState = OperationState.ready
private dynamic var state: OperationState {
get {
return stateQueue.sync(execute: {
rawState
})
}
set {
willChangeValue(forKey: "state")
stateQueue.sync(flags: .barrier, execute: {
rawState = newValue
})
didChangeValue(forKey: "state")
}
}
public final 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
}
// MARK: - NSObject
private dynamic class func keyPathsForValuesAffectingIsReady() -> Set<String> {
return ["state"]
}
private dynamic class func keyPathsForValuesAffectingIsExecuting() -> Set<String> {
return ["state"]
}
private dynamic class func keyPathsForValuesAffectingIsFinished() -> Set<String> {
return ["state"]
}
// MARK: - Foundation.Operation
public final override func start() {
super.start()
if isCancelled {
finish()
return
}
state = .executing
execute()
}
// MARK: - Public
/// Subclasses must implement this to perform their work and they must not call `super`. The default implementation of this function throws an exception.
open func execute() {
fatalError("Subclasses must implement `execute`.")
}
/// Call this function after any work is done or after a call to `cancel()` to move the operation into a completed state.
public final func finish() {
state = .finished
}
}
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
Run Code Online (Sandbox Code Playgroud)
这个Operation
子类有一些实现细节,我想帮助理解.
该stateQueue
物业的目的是什么?我看到它正在使用的get
和set
在的state
计算性能,但我找不到解释的任何文件sync:flags:execute
和sync:execute
他们所使用的方法.
NSObject
返回部分中三个类方法的目的是什么["state"]
?我没有看到它们被用在任何地方.我找到了NSObject
,class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
但是,这似乎没有帮助我理解为什么声明这些方法.
Rob*_*Rob 39
你说:
- 该
stateQueue
物业的目的是什么?我看到它被get和set的state
计算属性使用,但我找不到任何解释它们sync:flags:execute
和sync:execute
它们使用的方法的文档.
此代码"同步"对属性的访问以使其线程安全.至于为什么你需要做的是,看到的Operation
文件,其中建议:
多核注意事项
...当您进行子类化时
NSOperation
,必须确保从多个线程调用任何重写的方法都是安全的.如果在子类中实现自定义方法(如自定义数据访问器),则还必须确保这些方法是线程安全的.因此,必须同步对操作中的任何数据变量的访问,以防止潜在的数据损坏.有关同步的更多信息,请参阅" 线程编程指南".
关于这个并发队列用于同步的确切用法,这被称为"读写器"模式.读写器模式的这个基本概念是读取可以相互发生并发生(因此sync
,没有障碍),但是对于该属性的任何其他访问(因此async
具有障碍),写入决不能同时执行.这些都在WWDC 2012视频异步设计模式与块,GCD和XPC中描述.请注意,而视频概述基本的概念,它使用旧的Operation
和NSObject
语法,而不是仅仅的斯威夫特3及更高版本的语法["state"]
和NSObject
这里使用的语法.
你还问:
class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
返回部分中三个类方法的目的是什么state
?我没有看到它们被用在任何地方.我找到了isReady
,isExecuting
但是,这似乎没有帮助我理解为什么声明这些方法.
这些只是确保对isFinished
属性的更改触发属性的KVN的方法keyPathsForValuesAffectingValue
,AsynchronousOperation
以及super.start()
.这三个密钥的KVN对于异步操作的正确运行至关重要.无论如何,在键值观察编程指南:注册从属密钥中概述了这种语法.
start
您找到的方法是相关的.您可以使用该方法注册相关密钥,也可以使用原始代码段中显示的各个方法.
顺便说一句,这是super
您提供的课程的修订版,即:
你不能打电话@objc
.正如execute
文档所述(强调添加):
如果要实现并发操作,则必须覆盖此方法并使用它来启动操作.您的自定义实现不得
main
随时调用.
Operation
在Swift 4中添加所需.
重命名isReady
为use final
,这是isReady
子类的约定.
宣布#keyPath
为dynamic
财产是不恰当的.任何子类都应该有权进一步完善其willChangeValue
逻辑(尽管我们很少这样做).
使用didChangeValue
使代码更安全/健壮.
使用finish
属性时,您不需要手动KVN .本例中手动调用.finished
和stateQueue
不需要.
改变,state
以便它只移动到sync:flags:execute
状态if sync:execute
.
从而:
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)}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 7
使用Rob 的回答中更新的代码片段时,应该注意由此更改引起的错误的可能性:
- 更改完成,使其仅在 isExecuting 时才移动到 .finished 状态。
以上与 Apple文档背道而驰:
除了在操作取消时简单地退出之外,将取消的操作移到适当的最终状态也很重要。具体来说,如果您自己管理已完成和正在执行的属性的值(可能是因为您正在实施并发操作),则必须相应地更新这些属性。具体来说,必须将finished返回的值改为YES,将执行返回的值改为NO。即使操作在开始执行之前被取消,您也必须进行这些更改。
在少数情况下,这会导致错误。例如,如果“maxConcurrentOperationCount = 1”的操作队列获得3个异步操作AB和C,那么如果在A期间所有操作都被取消,则C将不会被执行,队列将卡在操作B上。
归档时间: |
|
查看次数: |
4319 次 |
最近记录: |