Reputation: 645
I have an NSTableView whose NSTableColumn's value is bound to an NSArrayController. The arrayController controls a set of entities in my core data managed object context.
It works well, and when new entities are inserted into the arrayController via UI Actions the tableView selects the new item.
However I would to create new entities into the moc programmatically, then select the new object in the arrayController.
I have tried the following:
Image *newImage = [Image newImage]; // convenience method to insert new entity into mod.
newImage.title = [[pathToImage lastPathComponent] stringByDeletingPathExtension];
newImage.filename = [pathToImage lastPathComponent];
[self.primaryWindowController showImage:newImage];
The showImage: method is as so:
- (void)showImage:(Image *)image
{
[self.imagesArrayController fetch:self];
[self.imagesArrayController setSelectedObjects:@[image]];
}
However, the arrayController doesn't change its selection.
Am I doing it wrong? I assume that the newImage object that I created in the moc is the same as the object that the arrayController is controlling. If that's true, why isn't the arrayController changing its selection?
Hmm - testing that assumption, I have now checked the contents of the arrayController at runtime. The new image is not present - which I assume means that I have 'gone behind the back' of the bindings by manually inserting into the moc...
My newImage convenience method is as so:
+ (Image *)newImage
{
Image *newImage = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:[[CoreDataController sharedController] managedObjectContext]];
return newImage;
}
Is that not KVO compliant?
hmmm - Edit 2...
I assume that it is KVO compliant, as the new image appears in the UI. I'm now thinking that there is a delay between inserting the entity into the moc and the arrayController being informed.
I See from this question New Core Data object doesn't show up in NSArrayController arrangedObjects (helpfully shown to the right of this question by SO) that asking the arrayController to fetch: should help update the arrayController, but that the actual fetch: won't happen until the next time the runloop runs.
Should I delay the selection of the new object using a timer? That seems a little inelegant...
Upvotes: 2
Views: 981
Reputation: 2194
If you want to do this programmatically, the easiest is to directly add the new entity object to the NSArrayController, as easy as:
[self.imagesArrayController addObject:newImage];
That will do the trick of both adding the object to the controller, and selecting it.
One glitch though - I don't know what view (NSView, UIView) you use to present the NSArrayController's content - but NSTableView won't automatically scroll itself to reveal the newly added item.
I had to defer this (as adding happens in some later runloop) like thus:
NSUndoManager *um = self.managedObjectContext.undoManager;
[um beginUndoGrouping];
[um setActionName:NSLocalizedString(@"New Sample", NULL)];
PMWaterSample *sampleToAdd = [self createNewSample];
[self.samplesController addObject:sampleToAdd];
// Actual addition is deferred, hence we delay the scrolling too, on the main-thread's queue.
dispatch_async(dispatch_get_main_queue(), ^{
[self.samplesController rearrangeObjects];
// bring last row (newly added) into view
NSUInteger selectedIdx = [self.samplesController selectionIndex];
if (selectedIdx != NSNotFound) {
[self.samplesTable scrollRowToVisible:selectedIdx];
}
[um endUndoGrouping];
});
Hopefully that'll help. I never had to force the MOC to processPendingChanges. I still live with the feeling there's a better way to do this, and have the array controller make its embedding UI element scroll and reveal the new item, but I don't know how.
Upvotes: 0
Reputation: 645
Right - solved it, thanks to this question: New Core Data object doesn't show up in NSArrayController arrangedObjects
I had to call processPendingChanges: on the moc directly after inserting the new object.
So, my new creation convenience method is now:
+ (Image *)newImage
{
Image *newImage = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:[[CoreDataController sharedController] managedObjectContext]];
[[[CoreDataController sharedController] managedObjectContext] processPendingChanges];
return newImage;
}
Upvotes: 2