On Thu, Dec 15, 2016, at 02:29 PM, Charles Srstka wrote: > > On Dec 15, 2016, at 2:51 PM, Michael Ilseman via swift-evolution > > <swift-evolution@swift.org> wrote: > > > >> I don't think we should ever make it possible to mark an entire class as > >> `dynamic`. This just reintroduces the Obj-C problem, where many properties > >> support KVO, but not all, and there's no indication on the property itself > >> as to whether it supports it. > >> > > > > I’m not familiar enough with these kinds of bugs. Kevin, do you think the > > existing behavior aligns with or runs counter to safe-by-default? > > The problem Kevin describes is still here; ‘dynamic’ itself is quite > orthogonal to KVO as a concept. A method being declared ‘dynamic’ is no > guarantee that it actually supports KVO, and likewise, a method does not need > to be marked ‘dynamic’ in order to support KVO. You can, for example, either > call willChangeValue() and didChangeValue() in your willSet and didSet > accessors for a stored property, or for a computed property you can simply > implement the proper accessor methods to describe the dependencies, as in the > example below. > > import Foundation > > class Watcher: NSObject { > var kvoContext = 0 > > init(watched: Watched) { > super.init() > watched.addObserver(self, forKeyPath: "foo", options: [], > context: &kvoContext) > } > > override func observeValue(forKeyPath keyPath: String?, of object: > Any?, change: [NSKeyValueChangeKey : Any]?, context: > UnsafeMutableRawPointer?) { > if context == &kvoContext { > print("foo changed; now it's \((object as! > Watched).foo)") > } else { > super.observeValue(forKeyPath: keyPath, of: object, > change: change, context: context) > } > } > } > > class Watched: NSObject { > // not a single ‘dynamic’ member in here: > > class func keyPathsForValuesAffectingFoo() -> Set<String> { return > ["bar"] } > var foo: Int { > get { return self.bar } > set(foo) { self.bar = foo } > } > > var bar: Int = 0 { > willSet { self.willChangeValue(forKey: "bar") } > didSet { self.didChangeValue(forKey: "bar") } > } > } > > let watched = Watched() > let watcher = Watcher(watched: watched) > > watched.bar = 5 // outputs: "foo changed; now it's 5” > > - - - - - - > > All ‘dynamic’ does for you vis a vis KVO conformance is to automatically add > the willChangeValue() and didChangeValue() calls, *for a stored property.* > For a computed property, that doesn’t help you, if the dependencies aren’t > properly set up. For example, if we replace the Watched class with: > > class Watched: NSObject { > dynamic var foo: Int { > get { return self.bar } > set(foo) { self.bar = foo } > } > > dynamic var bar: Int = 0 { > willSet { self.willChangeValue(forKey: "bar") } > didSet { self.didChangeValue(forKey: "bar") } > } > } > > - - - - - - > > and then change the “bar” property, no notifications will be fired, even > though the value of ‘foo’ has indeed changed. So to a client of the class who > can only see its interface and not the source code, ‘dynamic’ is useless on > its own for determining KVO conformance.
The problem with that code isn't that `dynamic` doesn't work for computed properties. It does; if you mutate the `foo` property, you'll get the KVO notifications. The problem is you have one property that depends on another and you didn't set up the KVO machinery properly using automaticallyNotifiesObservers(forKey:) or automaticallyNotifiesObserversOf<key>() (incidentally in Swift you can write the latter as a `static let`, since that becomes a class method in Obj-C). So yes, `dynamic` by itself doesn't mean that the property supports KVO. But there are very few reasons to use `dynamic` outside of supporting KVO, so it's a pretty good signal that the property does support it. And conversely, not having `dynamic` doesn't mean that it doesn't support KVO, though if it does have manual KVO support using will/didChangeValue(forKey:) then it should be documented as such. > Bottom line: we really do need a new KVO-replacement system for Swift, one > that could actually advertise itself as part of the interface instead of > relying on documentation (especially since Apple isn’t interested in writing > it anymore; the number of classes and methods that just say “No overview > available.” in the documentation viewer in Sierra is really quite > astounding). Unfortunately, this is probably additive, and thus probably > won’t be heard until the next phase of swift-evolution. > > Charles > _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution