I have an NSTableView bound to an NSArrayController, and have registered an observer for whenever data changes to the data fields that the array controller manages. For example, here's a few of the addObserver calls:
[_arrayController addObserver:self forKeyPath:@"arrangedObjects.userName" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[_arrayController addObserver:self forKeyPath:@"arrangedObjects.enabled" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[_arrayController addObserver:self forKeyPath:@"arrangedObjects.lockSettings" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
After that, whenever data is changed by editing the table, my observer gets called just fine.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath compare:@"arrangedObjects.userName"] == NSOrderedSame)
{
// Great, we know a userName changed somewhere in the table, but which one?
}
}
The problem is, I need to know which one of the arranged objects triggered this. If I knew the tableview row that would work as well. It's nice to know that some userName changed somewhere, but I really need to know which one of the potentially hundreds caused the observer to be called.
Sorry for the old Objective C format of this, but some of us still have tons of legacy code to deal with.
View-based table view
Connect the text fields in the cells to an action method of the delegate of the table view. Get the row with NSTableView
method rowForView:
and the column with columnForView:
.
- (IBAction)editAction:(id)sender {
NSInteger row = [self.tableView rowForView:sender];
NSInteger column = [self.tableView columnForView:sender];
NSLog(@"Edited row: %ld, column: %ld", (long)row, (long)column);
…
}
Cell-based table view
Implement NSControlTextEditingDelegate
method controlTextDidEndEditing:
on the delegate of the table view. The edited row and column are editedRow
and editedColumn
of the table view.
- (void)controlTextDidEndEditing:(NSNotification *)aNotification {
NSInteger row = self.tableView.editedRow;
NSInteger column = self.tableView.editedColumn;
NSLog(@"Edited row: %ld, column: %ld", (long)row, (long)column);
…
}
Key
There are several ways to get the key:
NSString *key = [[tableColumnOrTextField infoForBinding:NSValueBinding] objectForKey:NSObservedKeyPathKey]; // something like "arrangedObjects.name"
NSRange aRange = [key rangeOfString:@"."];
if (aRange.location != NSNotFound)
key = [key substringFromIndex:aRange.location + 1];
Bindings solution (no coding required)
Edit the values in a detail view. Bind the text fields and other controls to controller key selection
of the array controller. "Allowes Editing Multiple Values Selection" is switched on by default. Works for cell-based and view-based table views.