Your reply was quite helpful and I quit trying to figure how to get bindings working with this. Too much behind the scenes magic wasting my time.
Once I knew I was looking for a solution avoiding bindings, I found a couple gems in the TableViewPlayground sample code that I am pretty sure are not explicitly mentioned in the documentation. Below are details of what I had to do to get a tableView operating without bindings, which IMO, is far easier than bindings once you are aware of the process.
VERY IMPORTANT KEYS to building View based DATASOURCE TableViews
1. USE BASIC UI items (NSButton), NOT NSTableCellView
2. Contrary to #1, you can use NSTableCellView for TextFields, imageViews IF... see below.
3. Add your basic UI Items directly to the NSTableColumn, delete provided the NSTableCellView.
4. Carefully implement tableView:inTableView viewForTableColumn:inTableColumn row:inRow.
Maybe (probably) I am blind, but I trusted the default mechanisms in Interface Builder regarding
building tables. Well, they are probably alright if your table contains nothing but text fields
and a static number of columns and you use bindings.
My implementation called for checkboxes and I also wanted to be able to change the number of
table columns at run time. Just having checkboxes requires knowing the following.
When Interface Builder creates a default tableView and you set the number of columns that you
want, it gives you a bunch of columns with NSTableCellView in each column.
If you then utilize bindings, this is possibly not a bad thing.
If you want to put a button into that column or use NSTableViewDataSource to supply your data
THIS IS A VERY BAD THING.
You must drag your Check Box Button (NSButton) to be the direct sub item of the column you want
it to be in. Then delete the NSTableViewCell - it is useless.
Make sure whatever class you are using to support your table is hooked up as both the dataSource
and the delegate for the TableView.
Then as the documentation says you need to implement:
NSTableViewDataSource METHODS
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return rowCount; //fetch your row count from your data source.
}
// this is called to supply the data for every column for every row, so be efficient as you can.
- (id)tableView:(NSTableView *)inTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
NSString *colName = [tableColumn title]
{
id aRecord = [self objectAtIndex:row]; //fetching a record from my data source
if ([colName isEqualToString: @"Number"]) {
return [[aRecord field:eNumberField] stringValue]; //my record returns a NSNumber, text field requires text.
}
else if ([colName isEqualToString: @"Name"]) {
return [aRecord field:eNameField];
} else {
bool isChecked = [aRecord column:colName field:eButtonField];
return [NSNumber numberWithBool:isChecked];
}
}
but NEVER:
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
You have to implement appropriate action methods for each of your column UI elements.
In your action method you can discover the row/column information with the following methods:
(tableView is assumed to be a (NSTableView*) field in the class that implements your action method that gets loaded
automagically because you tied the TableView to tableView in your class in Interface Builder)
- (IBAction)yourActionMethod:(id)sender
{
NSInteger theRow = [tableView rowForView:sender];
NSInteger theCol = [tableView columnForView:sender];
NSTableColumn *aColumn = [[tableView tableColumns] objectAtIndex:theCol];
NSString *colName = [aColumn title];
......
}
NSTableViewDelegate METHODS:
- (NSView *)tableView:(NSTableView *)inTableView
viewForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row
STUFF HERE IS REALLY IMPORTANT, without it nothing works.
1. The identifier of each table column UI element MUST be set and unique.
(text fields, buttons, ...)
2. You set it in Interface Builder when viewing the class for the UI element for the table column,
it is called "Identity". Whatever text you put here, you use to identify the column UI element in your code.
3. This "Identity" name is used in the makeViewWithIdentifier call below. This MUST be done.
4. IF you do have a text field and you DID leave the NSTableCellView in place, note
the code for "Number" and "Name" below. Assigning a value to the textField.stringValue must be done
here or else no values are ever displayed for this column ever.
(I suspect this is the case for the imageView field of a NSTableCellView as well)
5. Note that for my button for the third column I return the NSButton I put into my tableView
in Interface Builder. Even though I have a variable number of button columns in my table, I always
have one. For my table I have two text columns and everything else is a button.
6. Table Column titles are NOT the same as the UI element Identity, although maybe they could be.)
7. Note that I do NOT set the button's value in this code, for some reason Apple does not require it
like it does with the textField in a NSTableCellView.
8. I don't know how to create a column UI element "template" if there isn't one in a column in your TableView
that you created in Interface Builder. Maybe if you add your view in the objects list in IB???
Definitely does not work if your UI element is a separate view in your .xib file.
Here is some code (it originally came from Apple, just not their documentation):
- (NSView *)tableView:(NSTableView *)inTableView
viewForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row
{
NSTableCellView *result;
NSString *colName = [tableColumn title];
id aRecord = [self objectAtIndex:row]; //retrieve this row's record from my datasource.
if ([colName isEqualToString: @"Number"]) {
result = [inTableView makeViewWithIdentifier:@"Number" owner:self];
result.textField.stringValue = [ [aRecord field:eNumberField] stringValue];
return result;
}
else if ([colName isEqualToString: @"Name"]) {
result = [inTableView makeViewWithIdentifier:@"Name" owner:self];
result.textField.stringValue = [aRecord field:eNameField];
return result;
} else {
NSButton *theButton = [inTableView makeViewWithIdentifier:@"myCheckBox" owner:self];
return theButton;
}
}