NSFetchedResultsController does not use persistent cache
| Originator: | ben.dolman | ||
| Number: | rdar://16773579 | Date Originated: | 4/30/2014 |
| Status: | Open | Resolved: | |
| Product: | iOS SDK | Product Version: | |
| Classification: | Reproducible: | Always |
Summary: Under certain circumstances NSFetchedResultsController (FRC) does not use the persistent section cache. This results in section info being recalculated every time -[NSFetchedResultsController performFetch:] is called. Pre-conditions for this bug: 1. 64-bit platform 2. A core data model with a .xccurrentversion file (e.g. Good.xcdatamodeld/.xccurrentversion). This file does not normally exist unless you have more than one model version, but even adding it manually works for reproduction purposes. The presence of this file results in the inclusion of a .omo file in the final compiled core data bundle. If the .omo file is not present then the bug does not manifest. 3. In addition to the entity to be used by the FRC, there must be an additional entity whose name is lexically smaller than the primary entity. For example, if I am querying on the "Event" entity, then I need another entity lexically smaller, such as "AEntity". If the other entity is larger (e.g. "ZEntity") then the bug does not manifest. Under these conditions, then when calling performFetch: FRC *always* recalculates the section info cache, even if a matching one is present on the persistent storage. Steps to Reproduce: In the included example project there are two data models, "Good" and "Bad". Each model has an "Event" entity, which will be queried on using an FRC. Each model also has an "AEntity" entity. The only difference between these is the presence of a .xccurrentversion file in the "Bad" model. 1. Run the example project on a 64-bit device or simulator 2. Two options will appear in the root table view. "Good" and "Bad". 3. Tap "Good". Note the lag and the console output in which the section info is calculated for the first time. 4. Tap "Back". 5. Tap "Good" again. Note that there is no log and no console output this time because the section info cache is being used. 5. Tap "Back". 6. Tap "Bad". Note the console output in which the section info is calculated for the first time. 7. Tap "Back". 8. Tap "Bad" again. Note the console output that indicates that section info is being recalculated even though a valid cache file exists. Expected Results: After the initial cache seeding, there should be no additional log output as the cache should be used. Actual Results: The section info cache is recalculated every time we hit "Bad", as indicated by the log output. Version: 7.1 Notes: One workaround is to change entity names so that the desired entity is lexically smaller than all others. Unfortunately this won't work if you need to cache multiple entities. Configuration: 64-bit only. I can't reproduce on 32-bit.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
Workaround
I spoke with the Core Data engineers at WWDC 2014 who confirmed it was a bug and provided a workaround. The bug is in the
.omofile, which is just an optimized version of the.momfile. When you load the.momdwrapper from your code Core Data looks for the.omofile and uses that if it's there. If not it falls back to the.momfile. If you load the.momfile directly in your code instead of.momdthen you avoid this bug.Another option is to remove the
.omofile in a build scripts phase after compilation. Then no code changes are necessary.