Core Data: how to just delete and rebuild the data store?

后端 未结 3 835
逝去的感伤
逝去的感伤 2021-02-03 12:54

I\'m using Core Data in an iOS 7+ app that does not need to save user\'s data, all data the app needs is requested to services and it can be recovered at any time.

相关标签:
3条回答
  • 2021-02-03 13:30

    Case 1: You're using a SQLite store

    This applies if your store type is NSSQLiteStoreType. Even if you plan to delete your data from time to time, it's not a bad idea to stick to SQLite, as it gives you the flexibility to keep your cached data on disk as long as you wish, and only delete it when you change your model and you don't want to apply any migrations.

    Quick solution? Delete your NSPersistentStoreCoordinator's store at startup, when you're initializing Core Data. For instance, if you're using the default SQLite store, provided by Apple's boilerplate code:

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"cd.sqlite"]
    

    you can simply delete the file:

    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
    

    then use storeURL to add a new persistent store as usual.
    Your NSPersistentStoreCoordinator won't complain if you have a new model and you won't need any migrations, but your data will be lost, of course.

    It goes without saying that you can decide to use this solution when you detect a change in the data model, leaving the store alone if there's no change, so that you can preserve your cached data as long as necessary.

    UPDATE:

    As suggested by TomHerrington in the comments, to be sure you've removed the old store completely, you should also delete journal files, which might come back and haunt you in the future, if you don't take care of them.
    If your store file is named cd.sqlite, like in the example, the additional files to be removed are cd.sqlite-shm and cd.sqlite-wal.

    WAL journaling mode for Core Data was introduced as the default in iOS 7 and OSX Mavericks, as reported by Apple in QA1809.

    Case 2: Use an in-memory store

    As suggested, you could switch to an in-memory store, using NSInMemoryStoreType instead of NSSQLiteStoreType. Erasing the store is much easier in this case: all your data resides in memory, all of it will disappear when your app stops running, nothing will remain on disk for you to clean. Next time, you could potentially load a completely different model, without any migrations, as there's no data to migrate.
    However, this solution, implemented as it is, wouldn't let you cache data between sessions, which looks like something you'd like to do between app updates (i.e., the store must be erased only when the app is updated and the model changes, while it could be useful to keep it on disk otherwise).

    Note:

    Both approaches are viable, with their pros and cons, and I'm sure there could be other strategies as well. In the end, you should have all the elements to decide what the best approach would be in your specific case.

    0 讨论(0)
  • 2021-02-03 13:39

    Working Swift solution if you target iOS 9 or higher

    The shared CoreData manager:

    class CoreDataContext {
        static let datamodelName = "CoreDataTests"
        static let storeType = "sqlite"
    
        static let persistentContainer = NSPersistentContainer(name: datamodelName)
        private static let url: URL = {
            let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")
    
            assert(FileManager.default.fileExists(atPath: url.path))
    
            return url
        }()
    
        static func loadStores() {
            persistentContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
                guard let error = error else {
                    return
                }
                fatalError(error.localizedDescription)
            })
        }
    
        static func deleteAndRebuild() {
            try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: storeType, options: nil)
    
            loadStores()
        }
    }
    

    call loadStores only once in the appDelegate and deleteAndRebuild when you want to delete and rebuild the database :)

    0 讨论(0)
  • 2021-02-03 13:56

    I think destroyPersistentStoreAtURL method of NSPersistentStoreCoordinator is what you want.

    It will remove the data store and journal files and all other things that need to be removed.

    Look at Apple documentation.

    0 讨论(0)
提交回复
热议问题