Get newest object added to NSFetchedResultsController? - objective-c

Not even sure if this is feasible, but here's the use case:
I have a RootView tableview that uses NSFetchedResultsController to manage the list. I tap an add button, which presents the AdditionViewController. The AdditionViewController uses a separatemanagedObjectContext to create the new object. On Save, the object is passed back to the RootView, where the new object (in the new managedObjectContext) is merged into the main managedObjectContext. The AdditionViewController is then dismissed, revealing the RootView.
What I would like to do, is to push my DetailViewController with the new object loaded after the merge, so that when the AdditionViewController is dismissed, the full detail view is revealed.
How can I get the object that has just been added to the fetchedResultsController in order to pass it to the DetailViewController?
--UPDATE--
Still nothing on this. Let me try to explain what I need to do (hopefully) a bit better. If this is still confusing, ask questions. I'm having a hard time thinking of how to describe the problem.
I am fully aware how to push the Detail view underneath the modal addition view upon saving the new object. The problem is that the object I am saving is in its own fetchedReaultsController. I am merging this frc into the main fetchedResultsController, so if I try to sent the object to the detailview, I get a crash, because the object has been invalidated (due to the merge) by the time the modal addition view is dismissed, and the detailview calls viewWillAppear. That is what I am trying to get around. How can I figure out what object was just added to the main fetchedResultsController in order to send it to the detailViewController?
--UPDATE--
Adding a bounty for anyone who can tell me how to retrieve the most recently added object from a fetched results controller. Or how to retrieve a specific object from a fetched results controller without knowing it's indexPath.

Here's how I did it in an almost identical use case:
While the AdditionViewController is displayed, the user has the option of saving the item they created or cancelling out of the new item dialog. I communicated the user's choice back to the RootViewController.
If the user cancelled, remove the object you created from your context.
If the user chose to save, save the context and display the DetailViewController.

For the record, the answer was to grab the object ID of the object in the addingManagedObjectContext AFTER saving the context (since the ID changes after saving), and passing that ID to the main managedObjectContext after the merge. The full code required for this is below (if anyone has an easier way, let me know)
detailViewController.object = (customObject *)[[fetchedResultsController managedObjectContext] objectWithID:[[[[addingManagedObjectContext registeredObjects] allObjects] objectAtIndex:0] objectID]];
Thanks to frenetisch applaudierend for pointing me in the right direction.

Related

Accessing a NSManagedObject causes EXC_BAD_ACCESS

Update: Tidied up question and made it a bit clearer
I am getting EXC_BAD_ACCESS crashes on a NSManagedObject.
I have a Sentence managed object that I pass to a modal view (addStoryItem) like so:
addStoryItem.sentence = (Sentence*)[fetchedResultsController objectAtIndexPath:indexPath];
AddStoryItem is set to retain Sentence:
#property (retain) Sentence *sentence;
Sometimes the user needs to do something that shows another modal (on top of addStoryItem) - which doesn't affect this object, but it does take a copy of a NSMutableSet - sentence.audiosets
If I they do view this modal I get an EXC_BAD_ACCESS whenever I try to access or set the sentence object or its properties, once the user is returned to addStoryItem
There is a current managed object context & fetched results controller
everything works fine unless I show that modal view controller (which, afaik, doesn't have anything to do with the sentence object)
Zombies is on, but it doesn't tell me anything (BRAINS?)
Here's a simple summary of what goes on:
user selects row in tableview
I get object from table and set the modal's sentence property then display the modal with the fetchedResultsController
I display a string, image and set a nsset from the sentence to ui aspects of the modal
if the user needs to modify the nsset they display another modal, with a copy of the first nsset (which doesn't change or access the sentence object)
if I try to set a property in the sentence after closing the 2nd modal (or NSLOG sentence) - EXC_BAD_ACCESS.
As far as I'm concerned I own sentence. Other properties of addStoryItem are still hanging around in memory - but sentence isn't there when I try to get to it. Yes, I release sentence in addStoryItem's dealloc - but that's not being called (I have a log statement in there).
Can you help? Happy to provide more code or info. Pretty frustrated!
You are creating a new sentenceToUpDate in your didSelectRowAtIndexPath:. Surely, this reference will be forgotten as soon as you are out of that method.
Rather, you should assign the retrieved object to your retained property, like this:
self.sentence = [fetchedResultsController objectAtIndexPath:indexPath];
Now the instance should be retained as expected.
Another possible culprit is your copy of the NSSet. Try creating a new NSSet to make sure you are not effecting the entity:
NSSet *setToBePassedToModal = [[NSSet alloc]
initWithSet:entity.toManyRelationship];

How to refresh uitableview/nsmutablearray after adding object to underlying nsmanagedobjectcontext

I have a basic UITableViewController that displays a list of schools, fetched from a simple two-entity core data repository. The tableview is bound to an NSMutableArray of schools that is loaded from an NSManagedObjectContext.
I added a "add new school" button which presents the user with a form for adding a new school. When the user adds the new school and clicks "save", I save the new school object to the NSManagedObjectContext and pop the "add school" view from the navigation stack. I am sent back to the original uitableview and the new school IS NOT in the list.
I know that I need to refresh the tableview, upon return, but am unsure how. NOTE: if I exit the simulator and run the program again, the new school record appears, so I know it is getting added properly to the underlying store.
Pretty sure I need to implement an NSFetchedResultsController but that seems like a TON OF CODE for what seems to be something quite straightforward.
If NSFetchedResultsController is the only way, can someone direct me to a tutorial or a code listing that may show this flow?
Many thanks.
Phil
Try reloading the data in your viewWillAppear method:
- (void)viewWillAppear:(BOOL)animated {
[self.tableView reloadData]
}
PS: I'd still recommend you look in to using a fetched results controller. A lot of the code is boiler plate and you won't normally need to touch it.

What am I doing wrong with NSManagedObjectContext dependency injection?

I am trying to use NSManagedObjectContext dependency injection as recommended by Marcus Zarra -- I'm creating an M.O.C. in my AppDelegate and passing it as a retained property to each of my view controllers.
Generally this seems to work well, but in a modal table view controller that presents data via an NSFetchedResultsController, I only see what was in the database when the app was launched. That is, if the user adds data at runtime, it gets added correctly to the database, but does not appear when the modal ViewController is opened and the NSFetchedResultsController is created (using the injected NSManagedObjectContext). However, if I close the app and restart, then open the modal view controller, I do see the data added in the previous session.
Do I have to refresh the M.O.C. in some way prior to creating the NSFetchedResultsController? I am absolutely sure that the modal view controller and the NSFetchedResultsController are being created, and the fetch is being executed, AFTER the new user data has been entered.
To start, you should log the moc in both app delegate and your view controller to confirm that the moc in both places has the same address and is therefore the same object.
If it is, then most likely you've got an issue with the FRC's cache. Set the cache to nil and/or refresh the cache and see if that resolves it.

Cocoa: getting a Table View cell to send action messages

I'm really having trouble getting a Cocoa Table View cell to send action messages.
At the most basic level, in IB there is an action assigned for the NSTextViewCell object, and after editing and pressing Return nothing happens.
So I have an IBOutlet hooked up to the NSTextViewCell, and have been experimenting with NSActionCell messages to it. But the Table View seems to pretty much just ignore them.
I've also tried subclassing NSTextViewCell, but the methods I'm seeing all look like they want to pass values to the object from somewhere, not return a value from inside the object to configure its behavior.
I'm pretty new to programming and Cocoa -- can someone explain each thing that needs to be overridden and how and where to do it?
AFAIK, the cells in an NSTableView won't send action messages out to your application, they're sent to the NSTableView so it can update its data. NSTableView itself tries to be pretty clever and update your data directly, rather than just telling you something changed, so depending on what you're trying to do and what the data source for the table is, you have a few options.
If you're using an NSTableViewDataSource object to populate the table, it's simple; just implement tableView:setObjectValue:forTableColumn:row: and the NSTableView will call that every time something is edited.
If you're using Cocoa data binding (for example, using an NSArrayController to bind an array of objects to the table,) then as long as everything is wired up correctly, the data should just automagically get updated in the source objects when the table is edited. If you need to take special action, then you can do whatever you need to in the property setter of your data class.
I haven't tried it yet, but could work...
NSCell *cellYouWant = [tableView preparedCellAtColumn:tableView.clickedColumn row:tableView.clickedRow];

NSTableView -setDataSource not working when triggered by FSEvents

So here's what I've got:
An NSTableView with an NSMutableArray data source
FSEvents monitoring a folder that contains the file that contains the data for the table view (Using SCEvents for Objective-C abstraction goodness)
The FSEvents triggers the same function that a reload button in the UI does. This function refreshes the table view with a new data source based on the contents of said file via setDataSource:.
And here's what happens:
If I make a change to the file, the FSEvent gets triggered and the refresh method gets called.
The array that the table view should be accepting does indeed include the changes that triggered the FSEvent.
setDataSource: gets sent to the NSTableView with the correct data source.
The changes do not appear in the table view!
But then:
If I hit the refresh button, which triggers the exact same method as the FSEvent, the table view gets updated with the new data.
I also tried replacing the FSEvent with an NSNotification (NSApplicationDidBecomeActiveNotification), but the same thing happens.
Anyone have any idea why this is happening?
Edit: For clarification, the jist of my question is this: Why does my NSTableView reload as it should when triggered by a button press, but not when triggered by an FSEvent or an NSNotification?
Edit: Thanks to diciu, I've figured out that in fact all of my UI references point to 0x0 when triggered by the event, but then have valid addresses when triggered by the button click. These objects are all declared in IB, so there's no instantiation or allocation for them going on in my code. So my question is now: what can I do to stop these pointers from pointing to nil?
We call reloadData on NSTableView when we have new data to add/remove to the table.
This might help, to force the NSTableView to redraw.
I'm not really sure if this is what your asking though. The wording of your question is kind of confusing, you state a series of events, but never a true question.
sounds like when you register for the event/notification, you're passing in a different instance of your controller class.
Have you tried calling your method from your FSEvent on a second pass of the run-loop?
[myObject performSelector:#selector(reloadAction:) withObject:nil afterDelay:0.0];
You're setting an NSArray directly as the data source of the table view?
That's not how NSTableView works. The data source must be an object that conforms to NSTableDataSource. NSArray doesn't. You write the data source yourself; it will probably be the same object that you currently have calling setDataSource:.
The other way would be to use Bindings.
Could it be that reference to table view within the scope of your refresh method is not valid?
I.e. are you sure you're not calling [nil reloadData] which does not yield any errors?
Your reference to your table view might be nil in the refresh code if you're set it before awakeFromNib or in some other circumstances.