繁体   English   中英

Swift中具有KVC属性的NSView

[英]NSView with a KVC property in Swift

我有一个自定义的NSView类,定义为:

class MyView: NSView
{
    var someText: NSString

    override func didChangeValueForKey(key: String)
    {
        println( key )

        super.didChangeValueForKey( key )
    }

    // other stuff
}

我想要做的是从此类外部更改someText的值,并didChangeValueForKey注意到someText已更改,因此我可以例如将视图的needsDisplay设置为true并执行其他一些工作。

我该怎么做?

您确定为此需要KVC吗? KVC在Swift中可以正常工作,但是有一种更简单的方法:

var SomeText: NSString {
    didSet {
        // do some work every time SomeText is set
    }
}

没有KVC机制,因为这不是KVC的目的。

在Objective-C中,您将显式实现setter(如果该属性最初来自超类,则可以重写该setter)并在那里进行工作。

在Swift中,正确的方法是didSet机制。

didChangeValueForKey()不是KVC的一部分,而是KVO(键值观察)的一部分。 不应覆盖它。 它旨在在实现手动更改通知时(与willChangeValueForKey()配对willChangeValueForKey()被调用。

但是,更重要的是,没有理由相信对于任何事物都不会观察到的属性,将完全调用它。 KVO使类陷入混乱,以便针对实际观察到的那些属性挂接到setter和其他变异访问器 更改此类属性(并支持自动更改通知)后,KVO会自动调用willChangeValueForKey()didChangeValueForKey() 但是对于不可观察的属性,不会调用这些方法。

最后,在某些情况下,例如索引集合突变访问器,KVO将使用不同的更改通知方法,例如willChange(_:valuesAtIndexes:forKey:)didChange(_:valuesAtIndexes:forKey:)

如果由于某些原因确实不想使用didSet ,则可以使用KVO来观察selfsomeText属性的更改,并处理observeValueForKeyPath(_:ofObject:change:context:) 但这是一种不好的,笨拙的,容易出错的,低效的简单方法。

KVO和didSet不互斥:

import Foundation
class C: NSObject {
    dynamic var someText: String = "" {
        didSet {
            print("changed to \(someText)")
        }
    }
}

let c = C()
c.someText = "hi"  // prints "changed to hi"

class Observer: NSObject {
    init(_ c: C) {
        super.init()
        c.addObserver(self, forKeyPath: "someText", options: [], context: nil)
    }

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        print("observed change to \(object!.valueForKeyPath(keyPath!))")
    }
}

let o = Observer(c)
c.someText = "test"  // prints "changed to test" and "observed change to test"

我要在Jaanus的答案中添加一点,要使属性KVC兼容,您应该将其声明为dynamic var someText: NSString

但是,如果您不需要KVC的所有didSet功能, didSet是您的最佳选择。

更新资料

至于didChangeValueForKey: –相反,它旨在通知您密钥的值已更改(如果不是由于Foundation涵盖的情况之一)。 您应该使用addObserver(_:forKeyPath:options:context:)并重写observeValueForKeyPath(_:ofObject:change:context:)来通知更改。

或者,您可以使用许多第三方解决方案之一,例如ReactiveCococa或Facebook的KVOController

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM