NSOperation属性覆盖(isExecuting/isFinished)

Eri*_*rik 24 macos nsoperation ios swift

NSOperation在Swift中进行子类化,需要覆盖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)
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

所以这是我提出的解决方案,但它感觉非常丑陋和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 }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Rob*_*Rob 29

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

但是,在定义asynchronous/ concurrent操作(即那些将异步完成的操作)时,调用will/ didChangeValueForKeyfor 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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,检查,看看是否_executing_finished已经改变并不重要,但编写自定义时,它有时是有用的cancel方法等.


更新:

不止一次,人们已经指出新的finished/ executing属性,NSOperation.h并得出结论,适当的KVO键将是finished/ executing.通常,在编写符合KVO标准的属性时,这是正确的.

但是NSOperationQueue没有观察finished/ executing键.它观察isFinished/ isExecuting键.如果不对isFinished/ isExecutingkeys 执行KVO调用,则可能会出现问题(特别是异步操作之间的依赖关系将失败).这很烦人,但这就是它的工作原理." 并发编程指南"的" 操作队列"一章的" 配置并发执行操作"部分非常清楚需要执行isFinished/ isExecutingKVO调用的主题.

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

  • 同意.但这并不是"NSOperation"/"NSOperationQueue"的实施方式.这是实际观察`isFinished` /`isExecuting`.这是非标准的; 它很烦人; 但它是如何工作的.我已经通过澄清更新了我的答案,并链接到相应键的演示(如果你没有发布'isFinished` /`isExecuting`则说明问题). (2认同)
  • 仅供参考:我使用Xcode 7.1 iOS 9.1 Swift 2.1转换并运行["适当的KVO的Github演示"](https://github.com/robertmryan/Operation-Test-Swift).`isFinished` /`isExecuting`KVO键PASS.`finished` /`execution`键失败. (2认同)

Dav*_*rry 24

从快速的书:

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

我想你会发现这个有效:

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

  • @David更接近,但是`NSOperation`正在观察`isFinished`和`isExecuting`通知,而不是`finished`和`execution`.因此,在您的示例中,您必须对`isExecuting`键名称执行KVN调用,而不是执行`execution`. (2认同)

Mar*_*ark 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")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 非常荒谬,Apple确实提供了开箱即用的功能.我们需要提出自己的自定义解决方案......为什么没有任何ConcurrentOperation类可以继承? (3认同)