只是想知道这是否可以在Swift 2.2,KVO中计算属性!?
即:
var width = 0
var height = 0
private var area : Double {
get {
return with * height
}
}
self.addOberser(self, forKeyPath: "area", ......
客户端代码是否会修改with或height触发器observeValueForKeyPath?
在参与市长类重构之前先检查一下。 KVO的语法很烦人,因为如果有人手头的答案(我假设答案是否定的),它甚至不值得去游乐场。
问候! 〜d
答案 0 :(得分:14)
该代码因两个原因而失败:
您必须将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
。
(无论何时willChangeValueForKey
或didChangeValueForKey
发生变化,您都可以致电width
和height
,但通常更容易实施keyPathsForValuesAffectingArea
。 )
因此:
class MyObject: NSObject {
dynamic var width: Double = 0
dynamic var height: Double = 0
dynamic private var area: Double {
return width * height
}
class func keyPathsForValuesAffectingArea() -> Set<String> {
return [ "width", "height" ]
}
func register() {
self.addObserver(self, forKeyPath: "area", options: [ .Old, .New ], context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
print("observed \(keyPath) \(change)")
}
}
let object = MyObject()
object.register()
object.width = 20
object.height = 5
输出:
observed Optional("area") Optional(["old": 0, "new": 0, "kind": 1])
observed Optional("area") Optional(["old": 0, "new": 100, "kind": 1])
答案 1 :(得分:1)
正如@Rob在回答中所述,从Objective-c
中观察area
dynamic
现在为willSet { }
和didSet { }
属性添加width
和height
,
两个属性的willSet
内添加此self.willChangeValueForKey("area")
并在didSet
添加self.didChangeValueForKey("area");
现在,每当宽度或高度发生变化时,area
的观察者都会收到通知。
注意:此代码未经过测试,但我认为它应该做到预期的
答案 2 :(得分:0)
为了避免 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
}
}