How to properly trim object graph brought in by NSFetchedResultsController?
Asked Answered
V

2

1

Without reference cycles NSFetchedResultsController can turn its managed objects into fault properly when they are not needed. But with reference cycles, it not, so I have to re-fault those objects myself. However, manually re-faulting objects managed by NSFetchedResultsController is dangerous. So I want know what you Core Data experts think is the best way to trim object graph brought in by NSFetchedResultsController. Thanks.

Update:

I believe normally FRC should be able to re-fault objects, even with reference cycles. I have the impression that it is not because of an old bug that I reported to Apple in 2012 whose state is still Open: FRC never re-faults newly inserted objects (after saving), so I have to manually re-fault them. Here is my test project: http://d.pr/f/Ohe3.

Vagrom answered 6/1, 2014 at 16:37 Comment(9)
That question seems to be about what happens when objects are deleted from the context, which is not the same thing as re-faulting them.Peonir
@Vagrom please review my comment regarding your updatePadraic
BTW, your bug report about the inserted items still hold true and the FRC does not re-fault newly inserted objects.Padraic
@DanShelly Aha, it seems I forget to comment out my "fix" to the original bug. So manual re-faulting is still needed anyway.Vagrom
only for inserted objects (after the save refresh the objects, otherwise you will encounter performance degradation)Padraic
@DanShelly But after saving moc, there is no easy way to tell newly inserted objects from existing objects.Vagrom
keep a reference to the objects that are tracked by the FRC and only refresh themPadraic
So the conclusion is: due to Core Data/FRC's bug I have to manually re-fault some of the objects tracked by FRC. In order to keep track of which of them are in this set I need to do extra housekeeping work which is not easy but messy. And if I do manual re-faulting, the danger is there for me: #20937996. So we are back to the starting point…Vagrom
CoreData has many annoying bugs and limitations. you will need to add custom logic no matter what you choose if your design reach a certain complexity level. as Apple put it "CoreData is not a silver bullet"Padraic
P
2

As I mentioned in my comments HERE, the FRC is responsible to fault-in or fault-out the objects it fetched.
Which in turn break any strong reference cycles between your managed objects.

You can test this by setting a breakpoint in your objects willTurnIntoFault method when scrolling a large enough table.

This is done with no regards as to what other objects reference these fetched objects (as far as I can tell).

Padraic answered 7/1, 2014 at 9:22 Comment(6)
Normally, FRC should be able to re-fault objects, even with reference cycles. Now I remember why I have the impression that it is not. It is because of an old bug that I reported to Apple in 2012 whose state is still Open. At that time, FRC never re-faulted newly inserted objects, even after saving moc. Today when I test using the old project, FRC does re-fault all objects(type: Event) correctly. However, the objects(type: Pic) on the other side of the cycle are not turned into fault. I have to manually re-fault them in Event's willTurnIntoFault. Here is my test project: d.pr/f/t4yNVagrom
Well ... my testing showed otherwise. So ... i opened your project and found the culprit. in your MasterViewController at tableView:didEndDisplayingCell:... you manually refresh the cell object. This cause performance depredations as you are not using the batch faulting offered by the FRC, and somehow this cause referenced items to linger in memory. after commenting this out, all was well.Padraic
Weird…I tested it again after commenting out my "fix" and found that FRC doesn't re-fault any object at all, not only newly-inserted objects. Are you sure it works for existing objects for you?Vagrom
yes, you have to scroll past the virtual cursor (at least a few hundred rows)Padraic
Yeah, I remember that. My bad memory…re-faulting by FRC only happens after some memory pressure.Vagrom
Regarding your last point, some of Apples apps have table cells that hold a strong reference to the managed object so they can do KVO on it so thought I would test it with this app. If you add the events to a mutable set in configureCell, i.e. the set maintains a strong reference to the objects, then they do not turn into faults.Flemish
D
-1

I think you should simply avoid strong reference cycles. Usually, there is no compelling reason to have to deal with the problem you describe.

For a detailed discussion, see Apple's Encapsulating Data chapter of the Programming with Objective-C guide where you will find a section titled Avoid Strong Reference Cycles.

Duly answered 6/1, 2014 at 18:57 Comment(1)
CoreData is build-in with strong reference cycles (think of a one-to-one relationship, both entities are retained by each other). Apple do specify that it is up to you to break this retain cycle by refreshing unnecessary objects. see HEREPadraic

© 2022 - 2024 — McMap. All rights reserved.