Swift 的计算属性上的 KVO
KVO on Swift's computed properties
在 Swift 中,计算 属性 上的 KVO 是否可行?
var width = 0
var height = 0
private var area : Double {
get {
return with * height
}
}
self.addOberser(self, forKeyPath: "area", ......
修改 with 或 height 的客户端代码会触发 observeValueForKeyPath 吗?
只是在进行市长 class 重构之前进行检查。如果有人手头有答案,KVO 的语法很烦人,甚至不值得去游乐场。 (我假设答案是否定的)
该代码无效有两个原因:
您必须将 dynamic
属性添加到 area
属性,如 “Adopting Cocoa Design Patterns” in Using Swift with Cocoa and Objective-C 下的“键值观察”部分所述.
您必须声明 area
依赖于 width
和 height
,如 “Registering Dependent Keys” in the Key-Value Observing Programming Guide 中所述。 (这适用于 Objective-C 和 Swift。)为此,您还必须将 dynamic
添加到 width
和 height
.
(您可以在 width
或 height
更改时调用 willChangeValueForKey
和 didChangeValueForKey
,但通常更容易实现 keyPathsForValuesAffectingArea
。)
因此:
import Foundation
class MyObject: NSObject {
@objc dynamic var width: Double = 0
@objc dynamic var height: Double = 0
@objc dynamic private var area: Double {
return width * height
}
@objc class func keyPathsForValuesAffectingArea() -> Set<String> {
return [ "width", "height" ]
}
func register() {
self.addObserver(self, forKeyPath: "area", options: [ .old, .new ], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("observed \(keyPath) \(change)")
}
}
let object = MyObject()
object.register()
object.width = 20
object.height = 5
输出:
observed Optional("area") Optional([__C.NSKeyValueChangeKey(_rawValue: new): 0, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 0])
observed Optional("area") Optional([__C.NSKeyValueChangeKey(_rawValue: new): 100, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 0])
正如@Rob 在他的回答中所说,从 objective-c
观察 area
dynamic
现在为 width
和 height
属性添加 willSet { }
和 didSet { }
,
在 willSet
内为两个属性添加此 self.willChangeValueForKey("area")
并在 didSet
中添加 self.didChangeValueForKey("area");
现在每次宽度或高度变化时都会通知 area
的观察者。
注意:此代码未经测试,但我认为它应该符合预期
为了避免 willChangeValueForKey
和 didChangeValueForKey
使用未经检查的字符串 属性 名称,我最近经常做的是计算 属性 private(set)
并创建一个私人 func
更新它。
import Foundation
class Foo: NSObject {
@objc dynamic private(set) var area: Double = 0
@objc dynamic var width: Double = 0 { didSet { updateArea() } }
@objc dynamic var height: Double = 0 { didSet { updateArea() } }
private func updateArea() {
area = width * height
}
}
在 Swift 中,计算 属性 上的 KVO 是否可行?
var width = 0
var height = 0
private var area : Double {
get {
return with * height
}
}
self.addOberser(self, forKeyPath: "area", ......
修改 with 或 height 的客户端代码会触发 observeValueForKeyPath 吗?
只是在进行市长 class 重构之前进行检查。如果有人手头有答案,KVO 的语法很烦人,甚至不值得去游乐场。 (我假设答案是否定的)
该代码无效有两个原因:
您必须将
dynamic
属性添加到area
属性,如 “Adopting Cocoa Design Patterns” in Using Swift with Cocoa and Objective-C 下的“键值观察”部分所述.您必须声明
area
依赖于width
和height
,如 “Registering Dependent Keys” in the Key-Value Observing Programming Guide 中所述。 (这适用于 Objective-C 和 Swift。)为此,您还必须将dynamic
添加到width
和height
.(您可以在
width
或height
更改时调用willChangeValueForKey
和didChangeValueForKey
,但通常更容易实现keyPathsForValuesAffectingArea
。)
因此:
import Foundation
class MyObject: NSObject {
@objc dynamic var width: Double = 0
@objc dynamic var height: Double = 0
@objc dynamic private var area: Double {
return width * height
}
@objc class func keyPathsForValuesAffectingArea() -> Set<String> {
return [ "width", "height" ]
}
func register() {
self.addObserver(self, forKeyPath: "area", options: [ .old, .new ], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("observed \(keyPath) \(change)")
}
}
let object = MyObject()
object.register()
object.width = 20
object.height = 5
输出:
observed Optional("area") Optional([__C.NSKeyValueChangeKey(_rawValue: new): 0, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 0])
observed Optional("area") Optional([__C.NSKeyValueChangeKey(_rawValue: new): 100, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 0])
正如@Rob 在他的回答中所说,从 objective-c
观察area
dynamic
现在为 width
和 height
属性添加 willSet { }
和 didSet { }
,
在 willSet
内为两个属性添加此 self.willChangeValueForKey("area")
并在 didSet
中添加 self.didChangeValueForKey("area");
现在每次宽度或高度变化时都会通知 area
的观察者。
注意:此代码未经测试,但我认为它应该符合预期
为了避免 willChangeValueForKey
和 didChangeValueForKey
使用未经检查的字符串 属性 名称,我最近经常做的是计算 属性 private(set)
并创建一个私人 func
更新它。
import Foundation
class Foo: NSObject {
@objc dynamic private(set) var area: Double = 0
@objc dynamic var width: Double = 0 { didSet { updateArea() } }
@objc dynamic var height: Double = 0 { didSet { updateArea() } }
private func updateArea() {
area = width * height
}
}