Re: Is willChangeValueForKey: always needed?
Re: Is willChangeValueForKey: always needed?
- Subject: Re: Is willChangeValueForKey: always needed?
- From: Chris Hanson <email@hidden>
- Date: Thu, 16 Nov 2006 22:11:45 -0800
On Nov 16, 2006, at 4:22 PM, David Catmull wrote:
Does didChangeValueForKey: always have to be preceded by a call to
willChangeValueForKey:?
Yes.
I have a case where the value in question is calculated based on
other values (which tab is selected, and whether a certain text
field has text), and the key is simply the name of the method that
calculates the value. So when one of those other values changes,
it's too late to say that the calculated value "will" change.
You should make this key's value on the values of the other keys.
Also, forgive me if I'm misinterpreting you here, but it sounds like
your application isn't necessarily leveraging the Model-View-
Controller pattern.
Instead of having a calculated controller or model key take the values
to use for its calculation directly from views/controls, you should
have your views/controls bound to some sort of model- or controller-
layer attributes, and then have whatever needs to take this calculated
value bound to its corresponding key.
For example, if I were writing a currency converter application, I
would bind my three text fields -- Amount, Exchange Rate, and
Converted Amount -- to the amount, exchangeRate, and convertedAmount
of a controller object. In that object's +initialize method would use
+[NSObject setKeys:triggerNotificationsForDependentKey:] to indicate
that any changes in either the amount or exchangeRate attribute will
result in a change in the convertedAmount attribute, and I would put
the logic to actually calculate the convertedAmount in the getter
method for that attribute.
I'm wondering about this because I have a situation where my
bindings don't seem to be updating immediately, causing a unit test
to fail.
Note that properties manipulated programmatically through object
controllers may not update immediately, in programmatic terms. See
all of the questions on the list where someone invokes -
[NSArrayController addObject:] in code and then attempts to get the
object that was just added from the controller.
- The unit test calls setValue:forKeyPath: on an NSObjectController
used to store the settings for my window's controls
A controller mediates between model and view objects, it shouldn't be
storing things on its own.
- My window controller object is observing that keypath, and in
response it calls will/didChangeValueForKey:@"canGo"
- The "Go" button's enabled property is bound to the window
controller's canGo key
- The unit test calls [goButton isEnabled] and unexpectedly gets NO
- The unit test calls [controller canGo] and gets YES as expected
I thought perhaps willChangeValueForKey: might be caching the "old"
value to see if it really does change, but the canGo method doesn't
seem to get called there.
The user experience that this test is trying to simulate does in
fact work correctly - when you type something into the text field
and the correct tab is active, the button becomes enabled.
There are a couple of issues with the above. The first is, as I
pointed out, is that you're expecting a property of a view to change
immediately after programmatically manipulating the model/controller
level object it takes the value of the property from.
The other issue is that you're trying to test your interface's
behavior from a unit test. Rather than trying to simulate user
interaction to test your model/view/controller interaction, you should
take a look at just checking the connections between the various
layers. You can check that your views are connected to your
controller and model objects very easily using the -infoForBinding:
method for bindings and the -target & -action methods for target/
action. You can check that your controllers are bound or otherwise
have appropriate references to your model objects the same way.
I've posted a couple of articles describing this strategy, which I
call "trust, but verify" (TBV) on my weblog:
Trust, but verify.
http://chanson.livejournal.com/118380.html
Unit testing Cocoa user interfaces: Target-Action
http://chanson.livejournal.com/148204.html
Cocoa is really amenable to this kind of unit testing. I hope to have
some time soon to post another article on how to use -infoForBinding:
to test the configuration of Cocoa bindings in a trust-but-verify
fashion.
Hope this helps!
-- Chris
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden