NSOperation属性覆盖(isExecuting / isFinished)

时间:2014-06-08 18:57:13

标签: ios macos swift nsoperation

我在Swift中继承NSOperation并需要覆盖isExecutingisFinished属性,因为我正在覆盖start方法。

我遇到的问题是如何保留键值观察(KVO),同时还能覆盖这些属性。

通常在Obj-C中,在类扩展readwrite定义中将属性重新声明为JSONOperation ()非常容易。但是,我在Swift中看不到同样的功能。

示例:

class JSONOperation : NSOperation, NSURLConnectionDelegate
{
    var executing : Bool
    {
        get { return super.executing }
        set { super.executing } // ERROR: readonly in the superclass
    }

    // Starts the asynchronous NSURLConnection on the main thread
    override func start()
    {
        self.willChangeValueForKey("isExecuting")
        self.executing = true
        self.didChangeValueForKey("isExecuting")

        NSOperationQueue.mainQueue().addOperationWithBlock(
        {
            self.connection = NSURLConnection(request: self.request, delegate: self, startImmediately: true)
        })
    }
}

所以这是我提出的解决方案,但它感觉非常丑陋和hacky:

var state = Operation()

struct Operation
{
    var executing = false
    var finished = false
}

override var executing : Bool
{
    get { return state.executing }
    set { state.executing = newValue }
}

override var finished : Bool
{
    get { return state.finished }
    set { state.finished = newValue }
}

请告诉我有更好的方法。我知道我可以创建一个var isExecuting而不是整个struct,但后来我有两个类似命名的属性,这些属性引入歧义并使其公开可写(我不想要)。

哦,我会为一些访问修饰符关键字做些什么...

3 个答案:

答案 0 :(得分:29)

正如David所说,你可以在子类属性覆盖中实现getter和setter。

但是,在定义asynchronous / concurrent操作(即那些将异步完成的操作)时,为{{1}调用will / didChangeValueForKey至关重要}和isFinished。如果你不这样做,操作就不会被释放,依赖关系不会被尊重,你会遇到问题isExecuting等等。)

所以我建议:

maxConcurrentOperationCount

顺便说一下,检查private var _executing: Bool = false override var executing: Bool { get { return _executing } set { if _executing != newValue { willChangeValueForKey("isExecuting") _executing = newValue didChangeValueForKey("isExecuting") } } } private var _finished: Bool = false; override var finished: Bool { get { return _finished } set { if _finished != newValue { willChangeValueForKey("isFinished") _finished = newValue didChangeValueForKey("isFinished") } } } _executing是否已更改并不重要,但在编写自定义_finished方法等时,它有时会很有用。


<强>更新

人们不止一次指出cancel中新的finished / executing个属性,并得出结论,相应的KVO密钥为NSOperation.h / {{1} }。通常,在编写符合KVO标准的属性时,这是正确的。

finished未遵守executing / NSOperationQueue键。它会观察finished / executing个键。如果您没有对isFinished / isExecuting密钥执行KVO调用,则可能会出现问题(特别是异步操作之间的依赖关系将失败)。它很烦人,但这是如何运作的。 并发编程指南Operation Queues章节中的配置并发执行操作部分非常清楚需要执行isFinished的主题/ isExecuting KVO致电。

虽然并发编程指南已过时,但它对isFinished / isExecuting KVO非常明确。并且可以轻松地凭经验验证指南仍然反映实际的isFinished实施。通过演示,在isExecuting中使用异步/并发NSOperation子类时,请参阅this Github demonstration of the appropriate KVO中的单元测试。

答案 1 :(得分:23)

从快速书中:

  

通过在子类属性覆盖中提供getter和setter,可以将继承的只读属性作为读写属性。

我想你会发现这有效:

override var executing : Bool {
    get { return _executing }
    set { 
        willChangeValueForKey("isExecuting")
        _executing = newValue 
        didChangeValueForKey("isExecuting")
    }
}
private var _executing : Bool

答案 2 :(得分:10)

Swift 3.0回复更新:

private var _executing : Bool = false
override var isExecuting : Bool {
    get { return _executing }
    set {
        guard _executing != newValue else { return }
        willChangeValue(forKey: "isExecuting")
        _executing = newValue
        didChangeValue(forKey: "isExecuting")
    }
}


private var _finished : Bool = false
override var isFinished : Bool {
    get { return _finished }
    set {
        guard _finished != newValue else { return }
        willChangeValue(forKey: "isFinished")
        _finished = newValue
        didChangeValue(forKey: "isFinished")
    }
}