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 }
这个Operation子类有一些实现细节,我想在理解上有所帮助.
> stateQueue属性的目的是什么?我看到它被状态计算属性的get和set使用,但我找不到任何解释sync的文档:flags:execute和sync:执行他们使用的方法.
> NSObject部分中返回[“state”]的三个类方法的目的是什么?我没有看到它们被用在任何地方.我在NSObject中找到了类func keyPathsForValuesAffectingValue(forKey key:String) – >设置< String>,但这似乎不能帮助我理解为什么声明这些方法.
- What is the purpose of the
stateQueue
property? I see it being used by get and set of thestate
computed property,but I can’t find any documentation that explains thesync:flags:execute
andsync:execute
methods that they use.
此代码“同步”对属性的访问以使其线程安全.关于为什么需要这样做,请参阅the Operation
documentation,其中建议:
Multicore Considerations
… When you subclass
NSOperation
,you must make sure that any overridden methods remain safe to call from multiple threads. If you implement custom methods in your subclass,such as custom data accessors,you must also make sure those methods are thread-safe. Thus,access to any data variables in the operation must be synchronized to prevent potential data corruption. For more information about synchronization,see 07001.
关于这个并发队列用于同步的确切用法,这被称为“读写器”模式.读写器模式的这个基本概念是读取可以相互发生并发(因此同步,没有障碍),但写入必须永远不会同时执行该属性的任何其他访问(因此与屏障异步) .这一点在WWDC 2012视频Asynchronous Design Patterns with Blocks,GCD,and XPC中有所描述.注意,虽然该视频概述了基本概念,但它使用了较旧的dispatch_sync和dispatch_barrier_async语法,而不是使用了同步和同步(flags:.barrier)语法的Swift 3及更高版本语法这里.
你还问:
- What is the purpose of the three class methods in the
NSObject
section that return["state"]
? I don’t see them being used anywhere. I found,inNSObject
,class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
,but that doesn’t seem to help me understand why these methods are declared.
这些只是确保状态属性更改触发属性isReady
,isExecuting
和isFinished
的KVN的方法.这三个键的KVN对于异步操作的正确运行至关重要.无论如何,这种语法在Key-Value Observing Programming Guide: Registering Dependent Keys中概述.
您找到的keyPathsForValuesAffectingValue方法是相关的.您可以使用该方法注册从属密钥,也可以使用原始代码段中显示的各个方法.
顺便说一句,这是您提供的AsynchronousOperation类的修订版,即:
>你不能调用super.start().正如start
documentation所说(重点补充):
If you are implementing a concurrent operation,you must override this method and use it to initiate your operation. Your custom implementation must not call
super
at any time.
>在Swift 4中添加@objc.
>重命名execute以使用main,这是Operation子类的约定.
>将isReady声明为最终属性是不合适的.任何子类都应该有权进一步细化其isReady逻辑(尽管我们很少这样做).
>使用#keyPath使代码更安全/健壮.
>使用动态属性时,不需要手动KVN.在此示例中不需要手动调用willChangeValue和didChangeValue.
>更改完成,以便只有isExecuting才会移动到.finished状态.
从而:
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.sync(flags: .barrier) { _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 } // 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 { finish() 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 isExecuting { state = .finished } } }