【问题标题】:Core Data: how to just delete and rebuild the data store?Core Data:如何删除和重建数据存储?
【发布时间】:2026-02-02 21:20:06
【问题描述】:

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

提前致谢

【问题讨论】:

  • 你试过内存存储吗?
  • @sim 有人告诉我使用SQLite 存储,但是...我在哪里可以找到有关内存选项的文档?
  • 在 addPersistentStoreWithType 而不是 NSSQLiteStoreType 中,只需使用 NSInMemoryStoreType 并照常使用 Core Data

标签: ios core-data core-data-migration


【解决方案1】:

案例 1:您使用的是 SQLite 商店

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

快速解决方案?在初始化 Core Data 时,在启动时删除 NSPersistentStoreCoordinator 的存储。 例如,如果您使用 Apple 的样板代码提供的默认 SQLite 存储:

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

您可以简单地删除文件:

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

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

不用说,当您检测到数据模型发生更改时,您可以决定使用此解决方案,如果没有更改,则不考虑存储,这样您就可以根据需要保留缓存数据。

更新:

根据 cmets 中 TomHerrington 的建议,为确保您已完全删除旧存储,您还应该删除日志文件,如果您将来可能会回来困扰您不要照顾他们。
如果您的商店文件名为cd.sqlite,如示例中所示,则要删除的附加文件为cd.sqlite-shmcd.sqlite-wal

正如 Apple 在QA1809 中所报告的那样,Core Data 的 WAL 日志模式是 iOS 7 和 OSX Mavericks 中的默认设置。

案例 2:使用内存存储

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

注意:

这两种方法都是可行的,各有利弊,我相信也可能有其他策略。最后,您应该拥有所有要素来决定在您的特定情况下最佳方法是什么。

【讨论】:

  • 我只是建议不要在您处于应用程序中间时删除持久存储文件,即在添加持久存储之后。
  • 你说得对。我认为这是理所当然的,因为我们正在讨论在应用程序更新中更改数据模型,这将在启动时完成,在初始化 Core Data 时。但是感谢您的建议,我会添加一个注释:)
  • 您还需要删除日志文件,因为持久存储中的一些(可能全部)数据实际上在这些文件中。
  • 我的日志文件从来没有遇到过任何问题。 @TomHarrington 您在不删除它们后是否遇到任何不一致?
  • 感谢@TomHarrington 的评论。我的日记文件还没有任何问题,但我明白你的意思。我的运气可能是由于我的经验有限。让我更新我的答案并提及您最好删除的其他文件(-wal 和 -shm)以完全确保您已删除旧数据。谢谢!
【解决方案2】:

适用于 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 和 deleteAndRebuild 中调用一次 loadStores :)

【讨论】:

    【解决方案3】:

    我认为NSPersistentStoreCoordinatordestroyPersistentStoreAtURL 方法是你想要的。

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

    Apple documentation

    【讨论】:

    • 非常感谢您的回答。我相信这是正确的。但是 - 考虑到 CoreData 对象(上下文、实体、PSCoordinator、PSStore 等)的层次结构和依赖关系,随时调用“destroyPersistentStoreAtURL”是否安全?在破坏之前不应该做一些“关闭”仪式吗?您在这方面有何经验?