Re: totally confused by bindings settings
Re: totally confused by bindings settings
- Subject: Re: totally confused by bindings settings
- From: Ken Thomases <email@hidden>
- Date: Wed, 4 Jun 2008 03:53:40 -0500
On Jun 4, 2008, at 12:05 AM, Daniel Child wrote:
I worked out a super basic bindings case where table columns display
the ivars of a Word class via bindings. Words have three ivars with
standard accessors. An ArrayController manages a table of these words
Hmm. An NSArrayController doesn't manage tables, it manages an array
(as its name implies). So, do you have an array somewhere with
instances of the Word class? Where is it? For example, is it a
property of File's Owner, with a key "words"?
, with appropriate bindings between the columns and ivars. It works
as expected. So far so good.
Now, however, I want to bind the same table to an intervening class,
WordList, which contains an array of Words.
Contains how? What is the interface of this WordList class? What
properties does it have?
I tried setting the ArrayController's class to WordList, and bound
the value of individual table columns to
ArrayController.arrangedObjects.wordList.<Word ivar>. (wordList is
the mutable array in the WordList class.)
That doesn't seem right. The Class Name should indicate what kind of
elements are in the array being managed. That's still Word, unless
I'm misunderstanding what you're trying to achieve.
Similarly, the Content Array binding of the NSArrayController should
refer to the array of Words maintained by the WordList instance
(perhaps as a key path from the File's Owner, or whatever).
Therefore, it doesn't make sense to have ".arrangedObjects.wordList"
appear in the key path of the table column bindings. The
arrangedObjects are already the words in the WordList instance.
Let's suppose that File's Owner has a property "wordList" that is a to-
one relationship to a WordList instance. Let's also suppose that the
WordList class has a property "words" which is the to-many
relationship to some instances of Word. Then, the NSArrayController's
Content Array binding should be bound to File's Owner with Model Key
Path "wordList.words". That is, this array controller is managing
access to the words of the wordList of File's Owner. Now, the table
columns would be bound to the NSArrayController, with the Controller
Key "arrangedObjects" and Model Key Path being whichever property of
an individual Word instance should be presented in the column. Note
that the table column bindings are pretty much unchanged from the case
without the WordList class. This is a reflection of the encapsulation
provided by the MVC design pattern and KVC/KVO/bindings. If the model
changes -- in this case, the array of words moving from being a direct
property of File's Owner to being a property of a WordList object held
by the File's Owner -- the controller which mediates between the view
and the model may have to changed, but the view itself need not.
That didn't work. It appears I can add and remove lines to the
table, but the values I type in do not display after I tab out to
the next column.
It's hard to know for sure what's going on without knowing the details
of the WordList class. I suspect, from what you described, that the
columns were trying to map to WordList objects, but that they had no
idea how to convert what you type (a string) into a WordList.
More importantly, could someone clarify the rhyme and reason for
choosing when to:
- binding the content arrangedObjects versus
- binding the value (of table cells) to arrangedObjects.<ivar> versus
- binding the contentArray to selection.<ivars?>
Apple's Figure 13 of Cocoa Bindings Programming Topics takes a huge
leap from the trivial case of two simple controls (slider and
textfield) to a maze of connections between and among columns and
controllers. I simply don't see when to choose among the various
options, or what they stand for.
In many cases, there's only one binding to make. For example, a table
column has a Value binding, but not a Content or Content Array binding.
For an NSArrayController, there are Content Array, Content Array For
Multiple Selection, Content Object, and Content Set bindings, which
can be confusing. You'll need to look in the Cocoa Bindings Reference
for the page on the NSArrayController bindings. The most common case
is to bind Content Array.
An NSPopUpButton also has a variety of content bindings. Again, check
the page for NSPopUpButton in the Cocoa Bindings Reference. In this
case, it's useful to do a full-text search for the combined keywords
"contentObject contentValues" (without the quotes) to find some
additional documentation. In particular, the 10.4 AppKit release
notes (of all places) have important guidelines on using those
bindings. They say:
Selection widgets (NSPopUpButton/NSPopUpButtonCell and NSMatrix) now
offer a contentObjects binding in addition to the content and
contentValues bindings (the contentObjects binding becomes available
only if content is bound). This allows you to bind the content of
the widget to an array (content binding), the displayed values to a
dependent array (contentValues binding - which needs to use a key
path that is an extension to the one of the content binding), and
the "represented" objects to be handled through the selectedObject/
selectedObjects bindings to another depdendent array (contentObjects
- which also needs to use a key path that is an extension to the one
of the content binding). For example, if you have an array with
dictionaries (that can be bound to a controller through the
"selection.dictionaries" key) which each have values for a key
"displayName" and a key "representedObject", you can bind content of
a pop-up button to "selection.dictionaries", contentValues to
"selection.dictionaries.displayName" and contentObjects to
"selection.dictionaries.representedObject" - the selectedObject will
then operate on the "representedObject" values, while the pop-up
displays the "displayName" values in the user interface. Of course,
if you do not use the contentObjects binding, the represented
objects are still the values in the array to which content is bound.
Now, as to the question of what to bind to (arrangedObjects,
arrangedObjects.key, selection.key, etc.), that depends on what you're
trying to accomplish. If you want to access all of the objects in the
array being managed by an array controller, you bind to that
controller's "arrangedObjects" controller key. If you want to access
a particular property of the objects in that array, you specify a
model key path to that property. If you don't want all of the objects
but just those that are selected, you bind to the "selection"
controller key of the controller which is tracking that selection.
And, again, if you want to access a specific property of the selected
object(s), you specify a model key path as well. There are also the
selectionIndexes, selectionIndex, and selectedObjects keys. See <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/CntrlSelection.html#//apple_ref/doc/uid/TP40002146-187723
> for discussion of when to use "selection" vs. "selectedObjects".
In Figure 13, there are several combatants. Each combatant has a list
of possible weapons to wield. There's an NSArrayController to manage
that list. But which list should it manage, exactly? It should
manage the list of available weapons for the _currently_selected_
combatant. The first NSArrayController is doing the tracking of the
selection of combatant. So, this second array controller is bound to
the "selection" of the first array controller to get at the selected
combatant, and then using the "weapons" model key path to get that
combatant's array of weapons.
The GUI designer wants the pop-up to contain all of the available
weapons for the selected combatant, so it's content is bound to the
arrangedObjects of the second array controller. As described in the
NSPopUpButton bindings reference page, the pop-up will use the -
description method to obtain a string from whatever kind(s) of objects
are in the weapons array. If that weren't appropriate, you could bind
the contentValues binding to arrangedObjects.name (assuming a weapon
has a "name" property).
The pop-up should, of course, show the current selectedWeapon of the
combatant as its selection. And, when the user picks a new weapon
from the pop-up, it should set the combatant's selectedWeapon. So,
the pop-up's selectedObject should be bound to the selected
combatant's selectedWeapon property. Once again, where's the
"selected combatant" being tracked? In the first array controller, as
its "selection" property. So, the pop-up's selectedObject binding is
bound to the first array controller, with Controller Key "selection",
and Model Key Path "selectedWeapon".
The fact that some tutorials employ a custom controller and others
don't is also confusing as I don't see the clear design rationale
behind one and the other. Presumably you need a custom controller if
you will have actions not provided automatically by the canned
controllers (add, remove, insert, next, etc.). But the rationale for
connections between the custom controller and NSController object
also don't see that clear to me.
Typically, custom controllers are different kinds of things from
NSController-derived objects. Search the Cocoa Fundamentals Guide for
the phrases "mediating controller" and "coordinating controller".
Cheers,
Ken
_______________________________________________
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