> On Apr 19, 2017, at 4:50 PM, Quincey Morris 
> <quinceymor...@rivergatesoftware.com> wrote:
> 
>> 3. Computed properties do not need to be dynamic, […].
> 
> This is also not exactly true. Computed properties that have only a getter do 
> not need to be dynamic, because they don’t generate any KVO notifications via 
> a setter, and so “dynamic” is irrelevant.
> 
> However, a computed property that has a setter will *not* produce the 
> expected notifications unless it is marked “dynamic”, even if marked “@objc”. 
> (I tested this to be sure.) There’s nothing special about computed vs. stored 
> properties in this regard.

I should add that if a computed property needs ‘dynamic’ in order for its 
notifications to fire, the property is not properly KVO-compliant. There are 
three ways this could happen that I can think of off the top of my head:

Case #1: Derived from another KVO property

> @objc dynamic var foo: String
> 
> @objc var bar: String {
>       get { return self.foo }
>       set { self.foo = newValue }
> }

The above will not fire notifications for bar. Making bar ‘dynamic’ appears to 
fix the problem, but it is in fact still not compliant; if foo changes, bar’s 
value is changed as well, but its notifications will not fire. The proper way 
to fix this is to add keyPathsForValuesAffectingBar.

Case #2: Backed by something not exposed to Objective-C

> enum Option: String {
>       case foo = “Foo"
>       case bar = “Bar"
>       case baz = “Baz"
> }
> 
> var option: Option
> 
> @objc var objcOption: String {
>       get { return self.option.rawValue }
>       set {
>               if let option = Option(rawValue: newValue) {
>                       self.option = option
>               }
>       }
> }

The above will not fire notifications for objcOption. Making objcOption 
‘dynamic’ appears to fix the problem, but if option is changed, objcOptions’s 
value will change as well, and its notifications will not fire. The proper way 
to fix this is to add willChangeValue(forKey:) and didChangeValue(forKey:) 
calls in option’s willSet and didSet accessors.

Case #3: It’s backed by something other than a property

> @objc var isFoo: Bool {
>       get { return UserDefaults.bool(forKey: “Foo”) }
>       set { UserDefaults.set(newValue, forKey: “Foo”) }
> }

The above will not fire notifications for isFoo. Making isFoo ‘dynamic’ appears 
to fix the problem, but if the “Foo” defaults key changes by some mechanism 
other than isFoo’s setter, isFoo’s value will have changed, but the 
notifications will not fire. The better solution is to register for changes on 
UserDefaults or NSUserDefaultsController via one of the several available 
mechanisms that Cocoa provides to do that and ensure that isFoo’s clients are 
notified when the underlying value changes.

Charles

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to