Can i separate the selection model from an NSTableView - cocoa

Is there any way how i can maintain my own data model of selected items in a NSTableView.
I find it either pretty slow or complicated to keep the state of selected items when i update the table model.

You can maintain your own NSMutableIndexSet for the selected row indexes. If you're binding the table view's columns to an array controller's arrangedObjects and the array controller's contentArray to an array you own, bind the array controller's selectedIndexes to your index set. If you're implementing a data source, be the view's delegate as well and implement the delegate methods relevant to managing the selection.

Related

Mac OS X - Adding and Removing Items From an NSOutlineView With Core Data

I want to add and remove items from an NSOutlineView and animate the changing view. In my OutlineViewController scene I have a NSTreeController bound to my Core Data Entity and my ManagedObjectContext. My NSOutlineView's Content and Selection properties are bound to my NSTreeController and the NSOutlineView > Table Cell View > Model Key Path is bound to the associated objectValue.propertyName.
Assume there is an 'Add' button. I am currently calling the NSTreeController's 'insertChild' method and pass in the Entity name. This works exactly as I want except there is no animation. Similar for the TreeController's removeObjectAtArrangedObjectIndexPath method.
I see that the NSOutlineView provides a insertItemsAtIndexes:inParent:withAnimation: method which would provide the animation but I'm unsure if this will liaise with Core Data and insert a new Entity into the model and I'm not sure how to use this to insert a new item as a child of the selected item?
Any advise very welcome.

How is NSTableView Content Sorted After Array Controller Add?

After adding a managed object in array controller class, the bound table view 'places' it into the correct date sorted order.
However, as the table view is building it's rows, the new object has been placed at the bottom of the array controller's content array using:
Edit: Solution: Don't use the array controller's content. The issue was in:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
....
// originally
NSManagedObject *ci = [[self.arrayController content] objectAtIndex:row];
// should be: (note arrangedObjects replacing content)
NSManagedObject *ci = [self.arrayController.arrangedObjects objectAtIndex:row];
....
}
The image below shows an example of the placement. Console output from within -tableView: viewForTableColumn: row: at left (from original code above) and ordering in the table view on right. LHR is the new object (notice date order ascending).
Tried:
Saving the moc right after adding newObject
Calling Array Controller's arrangeObjects method
Attempting to manually setSortDescriptors
Binding the table view's selection index to the array controller (for grins)
This is also messing up the selectedRow even though the row with LHR is selected in the table view right after adding. The only way to correct the array controller's order is to manually sort the column.
How can the array controller's content be in sync with the table view? Even more, why might they not be in the same order?
The array controller "arranges" its content. It does this by calling its -arrangeObjects: method. The default implementation filters the contents using the array controller's filterPredicate and then sorts it using its sortDescriptors. A subclass could override that method to arrange the content differently.
The arranged contents can be accessed using the arrangedObjects property. This is what corresponds to rows in the table view. So, you should always use this if you're indexing by a table row. For example:
NSManagedObject *ci = [self.arrayController.arrangedObjects objectAtIndex:row];
The array controller's sortDescriptors may be set via bindings (e.g. if the table view's sortDescriptors binding is bound to the array controller). Depending on how you set up the table view bindings, this may be automatic. For NSCell-based table views, you typically bind the table columns value binding and don't bind the table views bindings. In that case, the table view automatically binds its content, selectionIndexes, and sortDescriptors bindings to the same controller as its columns. For view-based table views, you typically don't bind table columns and have to bind those table view bindings explicitly if you want them bound.
You can also set the array controller's sortDescriptors programmatically.
Try invoking rearrangeObjects on the NSArrayController and then doing the selection you need subsequent to that in a dispatch_async block. It's maddening, but some of the bindings are deferred to the next runloop turn, so you can't simply add an object, call rearrangeObjects, and select the new object in synchronous code. You have to use GCD to schedule things
See this question/answer for more discussion. It's is the exact same issue. Adding an object and trying to select it.
Enabling the Auto Rearrange Content option of the Array Controller made it for me.

NSTableView rebuilds all cells when adding only one

I have a view-based NSTableView driven by an NSArrayController bound to a NSMutableArray as the content array.
When I add a new item to the data source, tableView:viewForTableColumn:row: is called for every item in the data source. I would expect the table view to leave existing items alone, and only call this for the new item.
I add a new item via the controller, like this:
[_arrayController addObject:newObject];
How do I prevent the table view from doing this? The performance impact is unacceptable.
Edit: It also clears the user selection

What is the simple way to bind an NSMutableArray to a single Colum NSTableView

Is there a simple way to bind a NSMutableArray made up of Strings to a Single column NSTableView without creating any new classes?
Make an NSArrayController in interface builder. Bind its Content Array to your mutable array, like so:
Then bind your table column to that array controller, like so:
(Note the self in the model key path field. That's what makes it work with an array of strings.)
Assuming you're using a view-based NSTableView, you must bind the entire table view (not the column) to the array controller's arrangedObjects. Then, bind the text field's value to the containing cell view's objectValue property.
This is documented here.
For cell-based NSTableViews, Amy Worrall's answer is the correct approach.

Table view not updating according to bindings - Part Two

Title borrowed from this question, of which this one is not a duplicate. See my answer there for what was wrong for that questioner; I'm the author of that answer, and my problem is not that one.
I have a table view with three columns, whose Value bindings are bound to three properties of the arrangedObjects of an array controller. The array controller's contentArray is bound to the visitationResults of my document object; the items in that array are instances of a model class (VisitationResult). I have also bound the array controller's selectionIndexes and sortDescriptors to properties of my document.
I am mutating my property through a couple of accessors:
- (void) addVisitationResult:(VisitationResult *)newVisitationResult {
[self insertObject:newVisitationResult inVisitationResultsAtIndex:[self countOfVisitationResults]];
NSLog(#"arrayController arrangedObjects: %#", [arrayController arrangedObjects]);
}
That NSLog statement runs, and confirms that the array controller is gathering and arranging my model objects. This means that I am going through my property and getting KVO notifications for my document (which proves that the earlier questioner's problem, that of bypassing the property, is not the problem I'm having).
I added NSLog statements in my model object class's accessor methods. One of them is being called—by the array controller, in order to sort the objects (that property is the sort key). The other two, which the array controller doesn't know about, never get called.
Thus, my table view remains blank.
I found the problem: It's because I had explicitly bound the selectionIndexes and sortDescriptors bindings of the table view.
This wasn't necessary, anyway: I just checked, and the documentation says:
selectionIndexes
Typically, selectionIndexes is bound automatically to the NSArrayController that the first NSTableColumn is bound to.
sortDescriptors
Typically this binding is created automatically, binding to the sort descriptors of the NSArrayController of the initially bound NSTableColumn.
It appears that not only is it not necessary, but binding either or both of these two will break the table view.

Resources