Update to NSManagedObject causes NSFetchedResultsController delete - ios

I have quite a frustrating problem that I have been struggling with for quite some time.
To provide some context and detail I have an iOS UISplitViewController application - standard master / detail stuff. The master view is a UITableView backed with an NSFetchedResultsController (which loads NSManagedObjects from a SQLite data store).
What seems to be happening is that any update within the details view (which can routinely cause updates to the 'master records' and are flushed to NSManagedObject's and ultimately the SQL data store) causes a DELETE operation on the NSFetchedResultsController.
I assume that this is because the write to the NSManagedObject property(s) are causing a fault of some kind, which in turn causes the NSFetchedResultsController to expunge it from it's cached result set. The end result is that records go 'missing' from the master view (e.g.: UITableCellView's are removed from the master UITableView).
The issue is that I don't want this to happen and I have no idea how to stop it...
Has anyone experienced this issue before and could possibly provide some guidance?
Thanks in advance,
Ben

I'm not sure if this answers your question, but I figured out the solution to a similar problem I was having. I was sorting the objects in my Core Data-backed UITableView by the first letter of the name of each object. In whatever tutorial I read, it told me to put a transient property 'NameInitial' in the NSManagedObject subclass that I would populate with the first letter of the name of that object. I then used that property as my sectionNameKeyPath to sort the objects into the proper sections in my UITableView.
I had a button on each cell that updated a property of the object associated with that cell, and I properly received NSFetchedResultsChangeUpdate messages in my didChangeObject delegate function. HOWEVER, sometimes, cells would get deleted and I would receive the NSFetchedResultsChangeDelete message for no apparent reason.
Then I noticed that the cells that were getting deleted had (null) as the NameInitial property for their associated object. I had forgotten that the transient NameInitial is only stored in memory, and so is not necessarily maintained all the time. Once I manually repopulated the NameInitial property each time I updated a cell, the deleting stopped. So if you are using a transient property to help sort/section your UITableView, this might be your problem.
Hope this helps, and good luck!
-Rick

Related

No changed section info althought that change causes controllerDidChangeContent call tableView.reloadData() and in turn invoke numberOfSections

This is very weird situtaion of using NSFetchedResultsController with core data in iOS development by Swift.
At first, FetchedResultsController contains only info of non-changed sections but no changed section info, althought that change causes controllerDidChangeContent method call tableView.reloadData method and in turn invoke numberOfSections method.
But subsequent manual invokes, e.g. in viewWillAppear, of the FetchedResultsController results in correct showing of the changed section info along with other non-changed section info.
In other words, fetched change of an attribute referred in sectionNameKeyPath via cloudkit in a background context was saved to viewContext which in turn saved it to persistent container. During the process, controllerDidChangeContent was invoked and tableView.reloadData was called. At that moment, in numberOfSections, no changed section info can be observed in the fetchedResultsController.sections, which only contains info of non-changed sections. I have set that attribute name as first sort descriptor in the fetch request associated with the fetchedResultsController.
I can't really find any clue of the illogical; any thought is welcome.
Issue found!!! Credit giving to Michael in answering the NSFetchedResultsController calls didChangeObject delete instead of update
Cause is my predicate using string interpolation for number value. After changing the use of number predicate, magic happens. Thanks Stackoverflow community!

Crash when deleting object from Core Data and toggling view controllers

I am making a NSFetchRequest for a NSManaged Object on my initial screen. I sometimes have a crash in a scenario when I :
switch to another view controller within my tab bar controller
make another fetch request with the same managed object type
delete a common managed objects which also appears in my initial VC's fetchrequest. The VC contains a table view.
save the managed context
toggle to the first VC, and reload the data
I am not using NSFetchResutltsController to manage these returned objects. The crash happens when my tableview reloads. I do make another request, and expected the deleted objects not be returned, but it does. When my cells are trying to read a property of the deleted object, it reads uninitialized and crashes. This happens about 1 out of 5 times when toggling between the 2 VCs. I am using performAndWait in all of my CoreData functions.
Is there a way to decouple the the relationship of the Managed Objects between the two screens? If not, how can I get my fetch request in the first VC, not return the objects that were deleted in the second VC, keeping them in sync?
A NSManagedObject is not like other other objects. It does not contain any information itself. It has a pointer to its context and an objectID. When you access it's properties it forwards the request to the context to get the information that it needs. So when an entity is deleted from the context the managedObject stops working and causes a crash. This is why in general I think it is a bad practice to EVER keep a pointer to a managedObject and ALWAYS access them using a fetchedResultsController even if only for one object, and only do a fetch if the managedObjects results are discards right afterwards.
There are two possible solutions, which you hinted to in your question. Either you can copy the values out of the managedObject, or you can use a fetchedResultsController. If you copy the values then it will appears as normal even after the entity is deleted. If you use a fetchedResultsController then the fetchedObjects property will be never contain deleted object, and the object will be inaccessible after it is deleted.
I would recommend using a fetchedResultsController. You don't need to be afraid of it. It is not a large overhead and it reasonable to use even if you are fetching only one object.

Serious Application Error. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. CoreData could not fulfill [duplicate]

My program does work like link below:
Update results of NSFetchedResultsController without a new fetch
show result of NSFetchedResultsController to UITableView
get new object from web service and store it to core data (in same view controller, with RestKit)
update table view with notification of NSFetchedResultsController delegate
The implementation of NSFetchedResultsControllerDelegate is copied from Apple's Core Data project and my predicated is:
[NSPredicate predicateWithFormat:#"isMyTest == TRUE"]
If the property update goes from TRUE to FALSE, it removes rows from the tableview (because the object for the row is in fetchedObjects of the NSFetchedResultsController)
However, if the property update goes from FALSE to TRUE, the NSFetchedResultsController notifies nothing, so the new data cannot be seen in table view. If I update BOTH NSFetchedResulsController and UITableView manually, it shows the new data.
I thought NSFetchedResultController watches all changes in persistent store, is it too big hope? :D
(I really want to do that because other view controller can update persistent store, then it is hard to update the view controller.)
If so, can you let me know how can I update NSFetchedResultsController in beautifully way?
(update)
in reference of NSfetchedResultsController, I read words below:
A controller thus effectively has three modes of operation, determined
by whether it has a delegate and whether the cache file name is set.
No tracking: the delegate is set to nil. The controller simply
provides access to the data as it was when the fetch was executed.
Memory-only tracking: the delegate is non-nil and the file cache name
is set to nil. The controller monitors objects in its result set and
updates section and ordering information in response to relevant
changes.
Full persistent tracking: the delegate and the file cache name are
non-nil. The controller monitors objects in its result set and updates
section and ordering information in response to relevant changes. The
controller maintains a persistent cache of the results of its
computation.
"Full persistent tracking" does not mean what I want? I set up cacheName, but it works same.
I thought NSFetchedResultController watches all changes in persistent
store, is it too big hope?
The FRC only automatically observes the objects returned by its fetch. This is normally not a problem as changes to objects monitored by an FRC should arise from either the tableview UI or a background context. In the former, the FRC is alerted to the change and in the latter, merging the foreground and background context will trigger the FRC to update.
It sounds like you've got code changing values but you're not notifying the FRC that you've made any changes. (If you got a tableview displaying all objects whose isMyTest == TRUE then obviously you can't access objects from the UI whose isMyTest == FALSE.) In that case, you need to register the tableview controller for:
NSManagedObjectContextObjectsDidChangeNotification
… notifications from the context so that you can tell the FRC to update for changes made outside its observation.
I'm sorry to my mistake, I tested with new test project.
CoreData DOES full-tracking of whole persistent store.
This means, if new object that is suitable to predicate of NSFetchedResultsController, delegate will notify it.

NSFetchedResultsControllerDelegate to update Table Cell after merging changes from another context

I have a TableViewController that's a NSFetchedResultsControllerDelegate. The data that this table is displaying is getting updated in another context (by RestKit) and getting merged upon notification. At this point if I were to run a query on the main thread's ManagedObjectContext I see the data that was updated by the other thread.
When that merge of context happens, the TableViewController, being a NSFetchedResultsControllerDelegate, even gets the controller:didChangeObject:atIndexPath:forChangeType:newIndexPath message. The issue I'm having is that the object (didChangeObject), still has the old data. I imagine this is so because whatever is calling this message just uses the current NSFetchResultsController to give me that object.
Why didn't the NSFetchResultsController's fetchObjects get updated from the context merge? Is there a way to have fetchObjects be updated by the context merge and perform this fetch again?
The answer was that the merge from changes marks the NSManagedObject's data as being in fault because it's stale. By default staleness interval is set to be infinite apparently. I would give credit to where I found this info but I can't find it now. Anyway, setting the NSManageObjectContext like so allows that context to see the updated info right away.
[__managedObjectContext setStalenessInterval:0];

Post-fetch sorting / Workaround for NSSortDescriptor + NSFetchRequest / Sorting a tableView

My quest to collect the scattered, magical pieces of code needed to create an animated and dynamically updating UITableView - artifacts hidden in the dark and ghastly depths of Apple Inc's feared dungeon, The Documentation - has with the help of the ever-friendly townsfolk and everyday heroes of Stack Overflow finally been completed.
But worry not, the end of this quest is but the beginning of a new one.
I have one UITableView. That tableView is hooked up to a NSFetchedResultsController. The FRC delegate methods are all up and running as pr. Apple's example code.
I have two NSManagedObjectContexts:
The Truth. This MOC is only inserted to / deleted from when the user adds or deletes an object.
The scratch pad. This is the MOC that the tableView's FRC is hooked up to. Any change here is reflected in the tableView with nice animations.
The scratch pad is seeded with objects from The Truth, but it is never saved. This means that I can insert and delete (show and hide) objects here to my heart's content, all while the tableView politely updates.
(To anyone reading this in an attempt to implement something like this I would say: get acquainted with [managedObjectContext objectWithID:id])
My question comes from the need to sort the tableView. As made clear to me by reading about NSSortDescriptor in conjunction with NSFetchRequest, using a sortDescriptor simply won't fly when one's using a SQLite store. The Docs say, "instead you should sort the returned array in memory". All-right then! But how do I go about doing that?
Where, in my logic as described above, do I inject this sorted array? Wherever I turn, there seems to be problems.

Resources