核心数据:如何删除和重建数据存储?

问题描述 投票:0回答:4

我在iOS 7+应用程序中使用

Core Data
,不需要保存用户的数据,应用程序需要的所有数据都向服务请求,并且可以随时恢复。因此,如果我在下一次应用程序更新中更改我的数据模型,我可以毫无问题地删除所有以前的数据并再次请求所有数据。但我不知道如何简单地用新的数据模型替换以前的数据模型,而不执行迁移,因为看起来我不需要这样做......

提前致谢

ios core-data core-data-migration
4个回答
13
投票

如果您的目标是 iOS 9 或更高版本,则可以使用 Swift 解决方案

共享CoreData管理器:

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()
    }
}

仅在 appDelegate 中调用

loadStores
一次,并且当您想要删除和重建数据库时调用
deleteAndRebuild
:)


11
投票

案例 1:您正在使用 SQLite 存储

如果您的商店类型是

NSSQLiteStoreType
,则这适用。即使您打算不时删除数据,坚持使用 SQLite 也不是一个坏主意,因为它使您可以灵活地将缓存数据保留在磁盘上,只要您愿意,并且仅在更改数据时才删除它。模型,并且您不想应用任何迁移。

快速解决方案?当您初始化核心数据时,请在启动时删除

NSPersistentStoreCoordinator
的存储。 例如,如果您使用的是 Apple 样板代码提供的默认 SQLite 存储:

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

您可以简单地删除该文件:

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

然后像往常一样使用

storeURL
添加新的持久存储。
如果您有新模型并且不需要任何迁移,您的
NSPersistentStoreCoordinator
不会抱怨,但您的数据当然会丢失。

不言而喻,当您检测到数据模型发生更改时,您可以决定使用此解决方案,如果没有更改,则保留存储,以便您可以根据需要保留缓存的数据。

更新:

正如 TomHerrington 在评论中所建议的,为了确保您已完全删除旧存储,您还应该删除日志文件,如果您不处理它们,它们将来可能会回来困扰您.
如果您的商店文件名为

cd.sqlite
(如示例所示),则要删除的其他文件为
cd.sqlite-shm
cd.sqlite-wal

Core Data 的 WAL 日志记录模式已作为 iOS 7 和 OSX Mavericks 中的默认模式引入,正如 Apple 在 QA1809 中所报告的那样。

案例2:使用内存存储

按照建议,您可以使用

NSInMemoryStoreType
而不是
NSSQLiteStoreType
切换到内存存储。在这种情况下,擦除存储要容易得多:所有数据都驻留在内存中,当您的应用程序停止运行时,所有数据都会消失,磁盘上不会留下任何内容供您清理。下次,您可能会加载完全不同的模型,而无需任何迁移,因为没有数据要迁移。
但是,按原样实现的此解决方案不允许您在会话之间缓存数据,这看起来像是您希望在应用程序更新之间执行的操作(即,仅当更新应用程序并且模型时才必须删除存储)更改,但将其保留在磁盘上可能会很有用)。

注:

这两种方法都是可行的,各有利弊,而且我相信还可能有其他策略。最后,您应该掌握所有要素来决定针对您的具体情况的最佳方法。


7
投票

我认为

destroyPersistentStoreAtURL
NSPersistentStoreCoordinator
的方法就是你想要的。

它将删除数据存储和日志文件以及所有其他需要删除的内容。

查看 Apple 文档


0
投票

好的,所以我需要在我的应用程序中执行此操作,最终编写了以下函数。

注意:在加载 CoreData 存储之前调用此函数(我将其添加到应用程序(它是一个 swiftUI 应用程序)的 init() 中,这似乎有效。

另请注意,上述答案指的是

   destroyPersistentStore(at: url, ofType: storeType, options: nil)

对我不起作用,因为它似乎没有删除 .sqlite-wal 文件或 sqlite.shm 文件。

class CoreDataContext {
    static let datamodelName = "cedarca"
    static let storeType = "sqlite"

    static let persistentContainer = NSPersistentContainer(name: datamodelName)



    class func deleteAndRebuild() {
    
        let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")
        let url1 = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).sqlite-shm")
        let url2 = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).sqlite-wal")
    
    
        if FileManager.default.fileExists(atPath: url.path) {
            do {
                try FileManager.default.removeItem(at: url)
                try FileManager.default.removeItem(at: url1)
                try FileManager.default.removeItem(at: url2)

            } catch {
                print(error)
            }
        
        }
    
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.