Swift 中带有 KVC 属性 的 NSView
NSView with a KVC property in Swift
我有一个自定义 NSView class 定义为:
class MyView: NSView
{
var someText: NSString
override func didChangeValueForKey(key: String)
{
println( key )
super.didChangeValueForKey( key )
}
// other stuff
}
我想做的是从这个 class 之外更改 someText 的值并让 didChangeValueForKey 注意到 someText 已更改,因此我可以,例如,将视图的 needsDisplay 设置为 true并做一些其他工作。
我该怎么做?
您确定需要 KVC 吗? KVC 在 Swift 中运行良好,但还有更简单的方法:
var SomeText: NSString {
didSet {
// do some work every time SomeText is set
}
}
我想在 Jaanus 的回答中补充一点,要使 属性 KVC 兼容,您应该将其声明为 dynamic var someText: NSString
。
但是,如果您不需要所有花里胡哨的东西哦,KVC,didSet
是正确的选择。
更新
至于didChangeValueForKey:
——它的目的恰恰相反,通知你键的值已经改变(如果不是由于基金会涵盖的情况之一)。您应该使用 addObserver(_:forKeyPath:options:context:)
并覆盖 observeValueForKeyPath(_:ofObject:change:context:)
以获得更改通知。
或者,您可以使用许多第 3 方解决方案之一,例如 ReactiveCococa or Facebook's KVOController
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"
没有用于此的 KVC 机制,因为这不是 KVC 的用途。
在 Objective-C 中,您将显式实现 setter(如果 属性 最初来自超级 class,则覆盖)并在那里完成您的工作。
在Swift中,正确的方法是didSet
机制。
didChangeValueForKey()
不是 KVC 的一部分,它是 KVO(键值观察)的一部分。它不打算被覆盖。它旨在在实施手动更改通知时调用(与 willChangeValueForKey()
成对)。
不过,更重要的是,没有理由相信它会在 属性 没有被任何东西观察到的情况下被调用。 KVO swizzles class 以便挂接到 setters 和其他变异访问器 以获取实际被观察到的那些属性 。当这样一个 属性 被改变时(并且支持自动改变通知),KVO 自动调用 willChangeValueForKey()
和 didChangeValueForKey()
。但是对于非观察属性,不会调用那些方法。
最后,在某些情况下,例如索引集合突变访问器,KVO 会使用不同的更改通知方法,例如willChange(_:valuesAtIndexes:forKey:)
和didChange(_:valuesAtIndexes:forKey:)
。
如果出于某种原因你真的不想使用 didSet
,你可以使用 KVO 来观察 self
在 someText
属性 中的变化并处理observeValueForKeyPath(_:ofObject:change:context:)
的变化。但这是做一件简单事情的糟糕、笨拙、容易出错、效率低下的方法。
我有一个自定义 NSView class 定义为:
class MyView: NSView
{
var someText: NSString
override func didChangeValueForKey(key: String)
{
println( key )
super.didChangeValueForKey( key )
}
// other stuff
}
我想做的是从这个 class 之外更改 someText 的值并让 didChangeValueForKey 注意到 someText 已更改,因此我可以,例如,将视图的 needsDisplay 设置为 true并做一些其他工作。
我该怎么做?
您确定需要 KVC 吗? KVC 在 Swift 中运行良好,但还有更简单的方法:
var SomeText: NSString {
didSet {
// do some work every time SomeText is set
}
}
我想在 Jaanus 的回答中补充一点,要使 属性 KVC 兼容,您应该将其声明为 dynamic var someText: NSString
。
但是,如果您不需要所有花里胡哨的东西哦,KVC,didSet
是正确的选择。
更新
至于didChangeValueForKey:
——它的目的恰恰相反,通知你键的值已经改变(如果不是由于基金会涵盖的情况之一)。您应该使用 addObserver(_:forKeyPath:options:context:)
并覆盖 observeValueForKeyPath(_:ofObject:change:context:)
以获得更改通知。
或者,您可以使用许多第 3 方解决方案之一,例如 ReactiveCococa or Facebook's KVOController
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"
没有用于此的 KVC 机制,因为这不是 KVC 的用途。
在 Objective-C 中,您将显式实现 setter(如果 属性 最初来自超级 class,则覆盖)并在那里完成您的工作。
在Swift中,正确的方法是didSet
机制。
didChangeValueForKey()
不是 KVC 的一部分,它是 KVO(键值观察)的一部分。它不打算被覆盖。它旨在在实施手动更改通知时调用(与 willChangeValueForKey()
成对)。
不过,更重要的是,没有理由相信它会在 属性 没有被任何东西观察到的情况下被调用。 KVO swizzles class 以便挂接到 setters 和其他变异访问器 以获取实际被观察到的那些属性 。当这样一个 属性 被改变时(并且支持自动改变通知),KVO 自动调用 willChangeValueForKey()
和 didChangeValueForKey()
。但是对于非观察属性,不会调用那些方法。
最后,在某些情况下,例如索引集合突变访问器,KVO 会使用不同的更改通知方法,例如willChange(_:valuesAtIndexes:forKey:)
和didChange(_:valuesAtIndexes:forKey:)
。
如果出于某种原因你真的不想使用 didSet
,你可以使用 KVO 来观察 self
在 someText
属性 中的变化并处理observeValueForKeyPath(_:ofObject:change:context:)
的变化。但这是做一件简单事情的糟糕、笨拙、容易出错、效率低下的方法。