Core Data:如何删除和重建数据存储?
Posted
技术标签:
【中文标题】Core Data:如何删除和重建数据存储?【英文标题】:Core Data: how to just delete and rebuild the data store? 【发布时间】:2015-03-13 07:54:54 【问题描述】:我在不需要保存用户数据的 ios 7+ 应用程序中使用Core Data
,应用程序需要的所有数据都请求服务,并且可以随时恢复。因此,如果我在下一次应用程序更新中更改我的数据模型,我可以删除所有以前的数据并再次请求它们。但我不知道如何简单地用新的数据模型替换以前的数据模型,而不执行迁移,因为看起来我不需要这样做......
提前致谢
【问题讨论】:
你试过内存存储吗? @sim 有人告诉我使用SQLite
存储,但是...我在哪里可以找到有关内存选项的文档?
在 addPersistentStoreWithType 而不是 NSSQLiteStoreType 中,只需使用 NSInMemoryStoreType 并照常使用 Core Data
【参考方案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-shm
和cd.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】:我认为NSPersistentStoreCoordinator
的destroyPersistentStoreAtURL
方法是你想要的。
它将删除数据存储和日志文件以及所有其他需要删除的内容。
看 Apple documentation。
【讨论】:
非常感谢您的回答。我相信这是正确的。但是 - 考虑到 CoreData 对象(上下文、实体、PSCoordinator、PSStore 等)的层次结构和依赖关系,随时调用“destroyPersistentStoreAtURL”是否安全?在破坏之前不应该做一些“关闭”仪式吗?您在这方面有何经验?以上是关于Core Data:如何删除和重建数据存储?的主要内容,如果未能解决你的问题,请参考以下文章
如何 VACUUM 一个 Core Data SQLite 数据库?
当应用程序从 4.0 中的任务列表中删除时,Core Data 存储消失