Re: Very basic table binding blind spot
Re: Very basic table binding blind spot
- Subject: Re: Very basic table binding blind spot
- From: Quincey Morris <email@hidden>
- Date: Thu, 02 Aug 2012 23:52:20 -0700
(reposted because of an apparent bounce)
On Aug 2, 2012, at 22:16 , Erik Stainsby <email@hidden> wrote:
> I do so wish there was a Complete Idiot's Guide to Cocoa Table Bindings … The very flexibility which I know must be their great virtue tends to obscure the clear path from my sight more often than not. Forest, trees, trees, forest … Oh! Something shiny!
I don't know that you have a problem with bindings as such. I think your problems are mainly with NSArrayController. On top of that, I think you might have some terminology wrong (possibly just typos).
> So tonight I have an NSArrayController (RSTableArrayController)
Ugh, subclassing an array controller (any NSController, really) is going to make you unhappy, eventually.
> which I have populated with dictionary objects of the form:
>
> [self.content addObject:[NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: key, [mvo valueForKey:key],nil] forKeys:[NSArray arrayWithObjects:@"label",@"value",nil]]];
Ugh, again, sorry to say. There are several warning flags here.
-- It's rarely easier to use a NSDictionary instead of define a custom class. A dictionary is a better solution only when the data objects have properties that cannot be determined until run time. If you know the properties of your data, step up and write the custom class right from the beginning. It'll be easier to write your code, and easier to debug.
-- By doing something like the above in an array controller subclass, you've muddied your MVC design pattern. The array of dictionaries *is* your data model -- or perhaps is just part of the data model -- but exposing its internal structural details, here in a mediating controller, is about 2 controllers away from where your data model really should be.
-- This code is not KVO compliant. This may not matter initially, if it happens before the view gets displayed, but it suggests you're going to think of your data (self.content) as an array, rather than as an indexed property of a data model object, and I'll bet you run into KVO compliance problems later.
> For this simple two column data I have a two column table, using Table View Cells (I'm going to have visual objects in place of the 'label' later on).
> I have set the identifier for the tableView columns very imaginatively to "label", and "value".
> The array controller is also < NSTableViewDataSource, NSTableViewDelegate >. I have implemented the following two delegate methods:
>
> - (NSInteger) numberOfRowsInTableView:(NSTableView *)aTableView {
> return self.content.count;
> }
>
> - (id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex {
> NSString * identifier = [tableColumn identifier];
> NSDictionary * dict = [self.content objectAtIndex:rowIndex];
> NSLog(@"%s- [d] %@: %@", __PRETTY_FUNCTION__, __LINE__, identifier,[dict valueForKey:identifier]);
> return [dict valueForKey:identifier];
> }
>
> In the nib, I have an ArrayController object of the class described above RSTableArrayController. It is wired up as the delegate and dataSource for the tableView.
The data source code seems fine (though I didn't peer at it line by line), but I think it's in the wrong place. The more usual placement in a window controller is better than putting it in the array controller. The less code references you have to the array controller, the easier your app will be write and debug. (Best of all: don't even define an outlet to the array controller. Unfortunately, that's not always feasible, but I believe it's always desirable.)
> And here is where I get lost time and again, tracing the appropriate path to the content and it's constituent data parts and binding them to the appropriate element in the tableView.
>
> » Scroll View
> » Table View
> » Table Column
> » Table Cell View
Do you mean "Table View Cell"? These days, "Table Cell View" means something quite different.
> » Static Text
> Text Field Cell
I'm not sure where these levels come from. In IB, the next level down from "Table Column" is some kind of cell, and there's nothing else. Did you perhaps create a view-based table instead of a cell-based table? Did you really want a view-based table (in which case you're implementing the wrong data source methods)?
> Given that the delegate method is called -[tableView: objectValueForTableColumn: row:] I should expect to bind the arrayController's objectValue
I'm not sure what you mean here. Array controllers don't have an "objectValue" property or binding. Array controller bindings have names like "contentObject" or "contentArray".
> in the Bindings Inspector to the ?node? in the object browser.
The normal thing is to bind the table column's "value" binding to the array controller's "arrangedObjects" controller key, specifying the model key that represents the property you want to display -- "label" in this case.
You *can* bind properties of the cell itself, but since certain properties bound from the table column are propagated *down* to the cell (when the cell for the column is requested) and certain cell properties are overridden (when the cell is prepared for use in a particular row/column context), things you do to the cell may get overridden.
_______________________________________________
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