Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an effective way to perform cascading deletes of objects from Core Data without hurting app performance?

The database in our app consists of objects nested several layers deep. For architectural reasons, it is not feasible for us to migrate away from this right now.

A high percentage of the data becomes expired on a daily basis. Our app performance degrades as the database grows in size.

Therefore, we need to find an effective way to keep the database small (at least in this release) and we are considering one of the following approaches:

  1. During applicationWillResignActive, delete NSManagedObjects by iterating thru all of the objects at the root level, calling delete on each one, and then allowing the deletes to be cascaded to the 3 layers of “to-many” objects. This involves one context save at the end that commits all this to the DB. This often it takes 10-20 seconds (on an iPhone 4) to delete the objects and Springboard terminates the process at 10 seconds. One major downside of this is that if the context save does not complete before the 10 second timeout, nothing gets deleted and the DB continues to grow each time the user runs the app.

  2. Delete the entire sqlite file inside didFinishLaunchingWithOptions or applicationDidBecomeActive, or inside applicationWillResignActive. This forces us to pop to the root of the app’s view controller stack so as to avoid attempting to display deleted data. The biggest downside of this is that the app has to download and parse data for several seconds before the user can do anything the next time they launch the app.

  3. Delete DB objects using beginBackgroundTaskWithExpirationHandler, after the user has hit the Home or Power button. There are unknowns associated with this that make it scary. Is anyone doing it (successfully) this way?

  4. Delete smaller groups of objects incrementally while the app is running. This increases the load on the device enough that it wrecks the smoothness of the tableviews, making them jittery. The amount of data already being parsed by API calls concurrent to deletion of old objects seems impractical here.

Any thoughts on the best practice for deleting objects in Core Data would be appreciated!

like image 705
jpswain Avatar asked Nov 03 '22 19:11

jpswain


2 Answers

orange80,

You should do your cascading delete in a background queue launched from within -applicationDidEnterBackground:. To keep from being terminated, you must use a background task ID.

I use this strategy in my frequently churning instance CD apps. By and large using this strategy, the user will never see the delete.

Andrew

like image 166
adonoho Avatar answered Nov 08 '22 03:11

adonoho


I ran into such a situation, where I didn't had the time to clean the data.

I solved the problem marking some key entities as deleted (an entity attribute), and deleting them (and cascade) for real later on. You do not have to mark every deleted entity, just the ones that makes sense to allow the postponed deletion and so the UI can easily know if any entity, marked or not, is about to be deleted. Sounds hard, but it shouldn't be if your data model is clean enough.

When your app restart, you either delete the entities and cascading - if this can't go to the end, you'll just restart the deletion when possible - or first iterate and mark all the deletable entities, possibly deleting them "one by one". This can be done in the background without messing up the UI (as the UI knows about the deletable entities). If you have performance issues doing so, you can process the deletions incrementally pretty easily.

That "mark and delete later" policy worked pretty well for me.

like image 39
fabrice truillot de chambrier Avatar answered Nov 08 '22 03:11

fabrice truillot de chambrier