Re: Cocoa bindings and reluctance to use NSPopupButon
Re: Cocoa bindings and reluctance to use NSPopupButon
- Subject: Re: Cocoa bindings and reluctance to use NSPopupButon
- From: "I. Savant" <email@hidden>
- Date: Mon, 19 May 2008 10:58:09 -0400
> I am not under any delusion that they are magic. It may appear that way to
> some because the only way to get them to work is to randomly choose one
> selection after another in the popups in the Bindings pane until you find
> one combination that 1) Doesn't cause the app to just bounce in the Dock on
> launch, and 2) Actually loads your popup or other object with the value of
> the model object that you wanted to bind it to.
Ahem ... I know this is meant as a sort of funny way of saying you
couldn't figure out the right way, but it's not *that* bad. There are
also a dozen threads in this list's archives where other people were
confused about NSPopUpButton's use with bindings. All contain very
clear and lucid explanations and/or references to outside tutorials,
examples, etc.
> content
> An NSArrayController instance that provides the content of the
> NSPopUpButton.
>
> Unless contentValues is also bound, the titles of the items in the
> NSPopUpButton are derived by invoking description for each of the content
> objects.
>
> Great. And this content is what exactly? Strings? Or what?
'Content' corresponds to the "representedObject" property of the
individual menu items. It can be anything. Whatever object is
represented by that item.
'Content Values' correspond to the titles of the individual menu
items. They can be your 'item.name' or whatever you prefer. If
unbound, as the documentation clearly states, the represented object's
'description' is used.
> I don't want an array, I want the single item that the user selected in the
> @#(#)*# popup!! If "returned by selectedObject" is an array, how do I know
> which of the items in the array is the selected one?
Believe it or not, this is (and I hesitate to mention this given the
vitriol others have expressed) covered by the conceptual documentation
on Bindings. You know the selected item by asking the controller to
which your popup's attributes are bound for its selection. That's a
big part of what Bindings is for - it's your controller's
responsibility to provide the items (from the model) to select and to
reflect that selection so it can be used by other controllers. Your
model object nor other views need know anything at all about that
popup. They need only know what 'Foo' instance is selected in your
'Foo Controller'. Therefore, that's the goal of this abstraction.
> See now why people get driven nuts by this documentation?
Yes. Well, I don't see *now*, because I went through the same
learning curve several years ago when Bindings was introduced. It
truly is an advanced topic.
> Understanding target/action is very simple because they make sense
> and the documentation is good. But being proficient with target/action tells
> you nothing about Bindings.
No, it doesn't tell you about Bindings, but it tells you about the
rest of the "machine" which is *absolutely necessary* to contrast with
Bindings. It allows you to know when and where it's best (or not) to
apply the technology. Years later and I still use Bindings sparingly
because it's not a great fit for everything. I haven't always had the
'wisdom' to know where it's best to use it and griped and complained
(to myself) that it was inflexible. I realized I was missing the
point. It's not a replacement for anything, really, just another
option that's available for you to use *when it makes sense*.
> For that you need documentation on what is the
> content, what is the content objects, what is the content values, why is
> content objects different from content values, etc. This is so easy to
> explain - obviously someone coded it and it's very flexible - why the
> absolute reluctance to just document it?
Reluctance? I'd think it's more a matter of time, priorities, and
available labor. Someone has to set the priorities for the
documentation team and that person will never satisfy / agree with
everyone regarding those priorities. Send in feedback. Keep sending it
in. Be pedantic about every point, filing separate grievances. If
enough people do that, "the people have spoken" and the
priority-setter will take notice and most likely adjust accordingly.
Stating your concerns here really doesn't do much (eg, 'preaching to
the choir').
> As I said, I am not a newbie (except to Bindings), and it does not help me
> to be told not to use Bindings in a project whose purpose is to learn
> Bindings.
No, I imagine not. I believe you and I discussed that privately
(that was you, right? I've had several similar discussions off-list
about Bindings) and even though I still got the sense that there were
some key concepts you were missing or shaky on and that you needed to
review before continuing.
After you clarified the purpose of this project, I did not
personally suggest you 'give it up', but that you needed to review. If
that wasn't you, I apologize, but my point remains the same. Even if
the documentation doesn't spell this out, knowing the rest of Cocoa
well means you can automatically (or with a bit of help from the list)
'see' how things relate (eg, content mapping to 'represented object'
and 'selection' mapping to the controller's selection).
I think I can help a bit more:
Consider the entity "Person" in a generic address book app.
Somewhere, there's a primary array that contains all the people
(instances of Person in your model layer). You might have an array
controller "People List Controller" for the main 'source list'. In
this case, the selection is determined by the selected Person in a
table view.
Now imagine you have a special field in your address book that
allows you to bond one person instance to another via some to-one
"spouse" property. When you select a person in the People List, the
People List Controller's selection object is a single person instance.
Its selection indices are (respecting the case of multiple selection)
the indices of the objects in the array it's managing and arranging
(sorting).
All the controls in your detail view (where the name, number,
address, etc. are displayed) reflect the properties of that selected
person because you bound them to the array controller's
selection.name, or selection.phoneNumber keys). How do you provide a
popup control with the necessary information to allow a list of other
people to select for that selected person's "spouse"? Well in this
instance, you can use the same list of people from the existing array
controller. If on the other hand you want a filtered list (that, say,
filters out the currently-selected person since it can't be its own
spouse), you might need another array controller. In a typical
application, you might have several array controllers, all managing
the same array, but having their own distinct sort order, filter
predicate, and/or selection. It truly depends on what you're trying to
accomplish.
Anyway, in this example, the People Chooser PopUp's contents (its
represented objects) should be bound to the Selected Person's Spouse
Controller's arrangedObjects (an array of person instances). The
popup's Content Values should be bound to the array controller's
arrangedObjects.fullName key path (assuming "Person" has a -fullName
property, etc.). This gives you another list of people that is
displayed in the popup. Again, if you wanted a filtered list or a
differently-sorted list, using another array controller would be
necessary.
The conceptual problem comes with managing selection. The popup
needs to represent the -spouse of the selected Person of the People
List Controller, right? In our case, the popup's selectedObject should
be bound to the People List Controller's "selection.spouse". We use
the popup's selectedObject binding because the target of
"selection.spouse" is a person object.
In a slightly different example, say we have a "relationshipType"
property on our Person entity. Let's assume this is a static list of
types that the user can't modify and aren't likely to change (much or
at all): { Undefined, Friend, Family Member, Coworker }. In this case,
it'd be easiest to define some handy constants: { 0 = Undefined, 1 =
Friend ... }. The relationshipType property can be reduced to a simple
number. In this case, our relationshipType popup (in our detail view
that reflects the selected Person) only uses one binding:
selectedIndex. This is because in Interface Builder, we can manually
edit the popup's items to "hard-code" (I use that term loosely) the
list of relationship types. This is nice and easy, especially if this
static list *never* changes from version to version.
A better approach would be to bind the popup's selectedTag property.
This way, you could insert another type somewhere in the middle of the
list and the user's data won't have to be changed. If you add a new
type say, "Enemy" that corresponds to "4", but you move Enemy up to
come after the first "Undefined" entry, the selectedIndex would
scramble the meaning and point to the wrong thing in your new version.
Using the menu's tags, however, means that no matter where the menu
item appears in your popup's menu, if the relationshipType of the
selected Person is "4", the menu item labeled "Enemy" (with a tag of
'4') will be selected.
Now let's consider some pretty "Delicious Generation" approach to
selecting the spouse of the currently-selected Person in your master
list. Say a pretty interface pops up where on the left you have a
table view filled with your people. On the right, you have a similar
table that represents the possible spouses. Let's say that, to further
complicate matters, you want each list to be able to be filtered
and/or sorted every which way, independently of one-another.
Of course you're going to have two distinct selections: 1 is the
main person, 2 is the intended spouse ... you'll also have two
different states (sort, filter, etc.). Yet you're pulling from the
same primary array of people. In this case, it's clear you'll need two
separate array controllers. I trust I don't need to further outline
why; I've been typing for many minutes now. :-)
I hope this clarifies things for you.
--
I.S.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden