just wondering if this is possible in Swift 2.2, KVO on a computed property!?
ie:
var width = 0
var height = 0
private var area : Double {
get {
return with * height
}
}
self.addOberser(self, forKeyPath: "area", ......
Would a client code modifying the with or height trigger observeValueForKeyPath?
Just checking before engaging on a mayor class refactor. KVO's syntax being as annoying as it's is not worth even a playground if someone has an answer at hand (I am assuming answer is NO)
regards!
~d
That code won't work for two reasons:
You must add the dynamic
attribute to the area
property, as described in the section “Key-Value Observing” under “Adopting Cocoa Design Patterns” in Using Swift with Cocoa and Objective-C.
You must declare that area
depends on width
and height
as described in “Registering Dependent Keys” in the Key-Value Observing Programming Guide. (This applies to Objective-C and Swift.) And for this to work, you also have to add dynamic
to width
and height
.
(You could instead call willChangeValueForKey
and didChangeValueForKey
whenever width
or height
changes, but it's usually easier to just implement keyPathsForValuesAffectingArea
.)
Thus:
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
Output:
observed Optional("area") Optional(["old": 0, "new": 0, "kind": 1])
observed Optional("area") Optional(["old": 0, "new": 100, "kind": 1])
As @Rob stated in his answer, make area
dynamic
to be observed from objective-c
Now add willSet { }
and didSet { }
for width
and height
properties,
inside willSet
for both properties add this self.willChangeValueForKey("area")
and in didSet
add self.didChangeValueForKey("area");
Now observers of area
will be notified every time width or height change.
Note: this code is not tested, but I think it should do what expected