Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

jeanlain

macrumors 68020
Original poster
Mar 14, 2009
2,481
968
Hi, I'm learning Cocoa bindings and I'm puzzled. Say you bind the values of two UI objects: an NSSlider and a NSTextField instances to a property (a float) of some NSObject's instance. Yo do the binding using the binding inspector. Moving the slider will change the object's property, whose value will be shown in the text field.
Typing a number in the text field will also adjust the slider's value accordingly.
Apple says syncing is done via KVC and KVO, if I understand what they say about the underlying technologies enabling Cocoa bindings. So I suppose that the slider and textfield are registered as observed of the object's float property (all done behind the scene).

But apparently it's not the case since modifying the value of the float property directly (in code) will not update the slider or the text field. If this relied in KVO, any changes in the property should be observed by the slider and the text field.
Similarly, changing the slider value in code (via slider.floatValue = 0.5;) does not change the text field or the float property.

It seems to me that KVO isn't actually in use, but that some messages are sent (using KVC) when user actions directly change the values the slider and the text field. For example, moving the slider would send a message to the NSObject instance to update its float property and to the textfield to change its value. So modifying the NSObject property directly would not do anything, because no observer is registered for changes in this property.

Am I correct?
 
But apparently it's not the case since modifying the value of the float property directly (in code) will not update the slider or the text field. If this relied in KVO, any changes in the property should be observed by the slider and the text field.

When you do this, you bypass the KVC mechanism which is required for KVO to function properly. Basically KVC allows for the KVO code to intercept the setter message calls for that property and use that to update other objects. The willChangeValue:ForKey: and didChangeValue:forKey: methods are used to indicate changes in the value to the KVO mechanism if you want to change a value directly (which you probably shouldn't be doing unless you have a really good reason).

Hope this helps. KVO/KVC is a bit tricky, but what helped me wrap my head around it was thinking about how I would build such a mechanism myself. It took the magic out of the equation and the whole thing made a lot more sense.
 
Thanks a lot. I probably haven't read carefully the KVO programming topics.
I replaced the myFloatProperty = 0.5 instruction with [self setValue: @(0.5) forKey: @"myFloatProperty"] and it's working as expected. :)

The willChangeValue:ForKey: and didChangeValue:forKey: methods are used to indicate changes in the value to the KVO mechanism if you want to change a value directly (which you probably shouldn't be doing unless you have a really good reason).
In my case I have several ways to zoom in a view that shows vector graphics. One is a slider, whose value is bound to the scale property of my view. Another is the pinch gesture. So it seems natural to use the magnification level from the pinch event and update the scale property directly. I'm not sure how I would do otherwise.
 
Last edited:
You don't have to use -setValue:forKey: (though it's OK to do so), you just need to use the accessor methods. So, do self.myFloatProperty = 0.5 or [self setMyFloatProperty:0.5].

In general, it's good programming practice to always use the accessor methods to access properties, and in fact there are hints that an upcoming version of Xcode's static analysis feature will flag direct access of instance variables (outside of accessor implementations, -init, and -dealloc) with a warning.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.