On Jan 18, 2014, at 9:45 PM, Roland King wrote:

> That was one point of confusion for me right at the start. IB binds the 
> 'value' property but as far as I could tell, NSTextField doesn't have such a 
> property, calling 'value' or 'valueForKey:@"value"' on it just raises as 
> exception, so I assumed bindings was doing something clever under the hood to 
> know that the value binding for an NSTextField actually means stringValue;, 
> or possibly it's using another method entirely which isn't called by 
> setStringValue:. 

This is an important lesson to understand.  The names of bindings are different 
from the names of properties.  Both bindings and properties are "attributes" of 
a class or object, but they are not the same thing.  Sometimes they correspond, 
but they don't have to.  A binding name is just something that can be used with 
the methods of the NSKeyValueBindingCreation and NSPlaceholders protocols.  The 
class which adopts one of those protocols interprets the name however it wants.


On Jan 18, 2014, at 10:17 PM, Roland King wrote:

> So it would seem that only a user-initiated change of the value fires the 
> binding in reverse (which is what the example binding code in the Apple docs 
> suggests) but setting the stringValue into the thing directly, doesn't. 
> That's a surprise, I expected that either way of setting the value would 
> result in the binding firing. I can see from the stack trace that the binding 
> code is triggered directly from the textFieldShouldEndEditing: method. 

I suggest you take a look at the Cocoa Bindings Programming Topics: How Do 
Bindings Work? article 
<https://developer.apple.com/library/mac/documentation/cocoa/conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html>.

The point is not that that's how bindings are _necessarily_ implemented for the 
Cocoa classes which support bindings.  The point is to illustrate that how 
bindings behave is entirely up to the class which implements them.  Also, 
consider what the -observeValueForKeyPath:… method shown ultimately does when 
it sees a model-initiated change.  It sets its own "angle" property.  If 
setting its property caused it to set the property on the model through the 
binding key path, it might get into an infinite loop.


On Jan 18, 2014, at 10:39 PM, Roland King wrote:

> On 19 Jan, 2014, at 12:25 pm, Quincey Morris 
> <quinceymor...@rivergatesoftware.com> wrote:
> 
>> Alternatively, don’t use ‘set<anything>’ on the text field at all, but let 
>> the Browse button action method update the *data model*, and then let the 
>> binding change the text field. This may seem weird, because the button 
>> action method would have to apply the reverse transformer itself, but it’s 
>> actually cleaner, because it doesn’t make the button behavior depend on the 
>> text field.
> 
> That's what I eventually did. It's cleaner because the Browse button (and 
> NSOpenPanel) produce an NSURL anyway, which I set right onto the model and 
> that then updates the text field with the string value. What I was trying, 
> and failing, to do before would have turned the URL into a String, set that 
> on the text field and have the transformer turn it back into a URL again, 
> which was contorted, but felt like it ought to have worked. 

I think it's cleaner to have the Browse button affect the model (through the 
controller) than for it to affect another view.  It's generally rare for one 
view to directly interact with another view.  Each view should interact with 
the controller and the controller should be responsible for updating other 
views.  Having views know about each other makes the user interface design 
fragile.  It's hard for you to redesign the interface, swapping out types of 
views for other types of views or the like.

Surely, the Browse button triggers an action method on the controller, anyway.  
So, it's not the button that knows about the text field (I hope).  The button 
just targets the controller.  The controller should then update state, either 
internal to itself or in the model, and tell views to update themselves to 
reflect that state.  This latter part is what bindings facilitate.

> The only bad bit about this is I had to make the model object a property of 
> the view so the browse button could set the URL property on it, with bindings 
> alone everything was in IB and the view object implementation had no 
> knowledge of the model object at all, it just set a string path onto itself 
> and the model was supposed to pick it up, except it didn't. 

I'm not entirely sure what you're talking about here.  If the text field is 
bound to the model (through the controller), then there's already a key path to 
the relevant part of the model.  The controller could simply traverse the same 
path as is used for the model key path used in the binding.  [I don't recommend 
using a key path string to do that, necessarily.  It should be able to access 
the properties in the chain in the normal way (calling accessors, perhaps with 
dot syntax).]

NSViewController has a handy representedObject property to serve as the, well, 
object which the view represents.  You can add a similar property to any 
subclass of NSWindowController that you create.

Regards,
Ken


_______________________________________________

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