我正在使用NSPersistentCloudKitContainerCloudKit在不同设备之间同步数据。它与新项目完美配合,但是当我将其与旧项目一起使用时,添加的旧数据NSPersistentContainer无法同步。
我要实现的是同步将添加到的旧数据NSPersistentContainer更改为NSPersistentCloudKitContainer。可能吗?
启用了二进制类型和“允许外部存储”的核心数据模型属性会导致 NSPersistentCloudKitContainer 同步机制崩溃。
这仅发生在接收设备上,这意味着上传到 CloudKit 是成功的,但是在 NSManagedContext 中从 CloudKit 下载会导致崩溃。
<NSSQLSaveChangesRequestContext: 0x281ec8420> , *** NSAllocateMemoryPages(28317598) failed with userInfo of (null)
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** NSAllocateMemoryPages(30318498) failed
Run Code Online (Sandbox Code Playgroud)
这显然是内存崩溃,但我不知道如何解决它,这似乎是一个 iOS 错误。
I'm trying to insert Array of dictionary in CoreData using NSBatchInsertRequest according WWDC 2019 (https://developer.apple.com/videos/play/wwdc2019/230/). The insertResult is nil, and my CoreData is empty.
let modelURL = Bundle.main.url(forResource: "CoreDataPerformance", withExtension: "momd")!
let model = NSManagedObjectModel(contentsOf: modelURL)!
let container = NSPersistentCloudKitContainer(name: "CoreDataPerformance", managedObjectModel: model)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
try container.viewContext.setQueryGenerationFrom(.current)
let moc = container.viewContext
moc.automaticallyMergesChangesFromParent = true
moc.perform {
let insertRequest = NSBatchInsertRequest(entity: Client.entity(), …Run Code Online (Sandbox Code Playgroud) 假设我们有一个有效的 NSPersistentCloudKitContainer 和一个名为 Item 的 CoreData 实体。假设我们想要在 iOS、iPad 和 Mac 应用程序之间同步。
我观看了有关同步 CoreData 和 CloudKit 的 WWDC 会议,并在我的 SwiftUI 应用程序中实现了基本同步。它可以工作,数据会发送到所有 3 台设备并自动同步。
但是在 Mac 上,如果不重新加载视图(以及在模拟器中(因为它们没有收到推送通知),数据就不会出现。它来了,但没有自动刷新。我还测试了模拟器到真实设备,有时它会自动同步,有时我需要重新打开应用程序才能看到更改。
我很好奇是否有一种可以与 NSPersistentCloudKitContainer 一起使用的强制获取方法。或者也许有人知道在使用 NSPersistentCloudKitContainer 和 SwiftUI 时手动重新获取数据的解决方法?
我还想在新数据开始出现时显示一个活动指示器,但不确定在代码中从哪里开始获取获取点?
我使用了 Apple 提供的这个 UIKit示例代码,并将其调整为在 SwiftUI 中工作。我还阅读了此处的所有文档。
这是我使用的persistentContainer代码:
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "AppName")
container.persistentStoreDescriptions.first?.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
} …Run Code Online (Sandbox Code Playgroud) core-data ios cloudkit swiftui nspersistentcloudkitcontainer
有时NSPersistentCloudKitContainer会在控制台中报告错误,如下所示:
*2020-04-14 16:41:27.725794+0100 ExampleApp[9736:8226377] [error] error: CoreData+CloudKit: -: <NSCloudKitMirroringDelegate: 0x282b944d0>: Sending \xe2\x80\x98NSCloudKitMirroringDelegateWillResetSyncNotificationName\xe2\x80\x99 with reason: \xe2\x80\x98UserPurgedZone\xe2\x80\x99* [NSCloudKitMirroringDelegate logResetSyncNotification:](1798) \nRun Code Online (Sandbox Code Playgroud)\n\n在我的代码中,我在加载持久存储时进行了错误处理,但此错误不会触发它,因为此错误是在存储加载后发生的。
\n\n我在哪里处理这些错误?我怎样才能看到代码中的这些错误?
\n当 NSPersistentCloudKitContainer 完成同步时如何得到通知?
我对上传Core Data 更改完成感兴趣,因为如果从服务器下载更改,Core Data 可以轻松通知。
我的应用程序使用 CoreData 和 iCloud 作为后端。多个设备可以访问 iCloud 数据库,因此.public。
本地 CoreData 存储与 iCloud 使用NSPersistentCloudKitContainer.
我根据Apple 的建议使用历史跟踪。
在那里,Apple 建议在可能的情况下修剪历史记录。他们说
由于持久历史跟踪事务会占用磁盘空间,因此请确定清除策略以在不再需要它们时将其删除。在修剪历史记录之前,单个看门人应确保您的应用程序及其客户端已经使用了他们需要的历史记录。
最初这也是在 26:10 开始的WWDC 2017 演讲中提出的。
我的问题是:我如何实现这个单一的看门人?
我认为这个想法是单个实例知道应用程序的每个用户最后一次同步他们的设备的时间。如果是这样,则可以修剪该日期之前的交易历史记录。
但是,如果用户同步了本地数据,然后很长时间不再使用该应用程序怎么办?在这种情况下,在该用户再次同步本地数据之前,无法修剪历史记录。所以历史数据可以任意增长。在我看来,这是一个我不知道如何解决的核心问题。
上面引用的 Apple 文档建议:
与获取历史记录类似,您可以使用 deleteHistory(before:) 删除早于令牌、交易或日期的历史记录。例如,您可以删除超过 7 天的所有事务。
但这并不能解决我心中的问题。
除了这个一般问题,我的想法是在公共 iCloud 数据库中有一个 iCloud 记录类型,它直接为每个设备存储(即没有 CoreData)本地数据库更新的最后日期。由于所有设备都可以读取这些记录,因此很容易确定所有本地数据库的最后一次更新时间,并且我可以在此日期之前修剪历史记录。
这是处理问题的正确方法吗?
我使用 NSPersistentCloudKitContainer 将对象保存在 CoreData + CloudKit 中。我集成了一个共享功能,可将对象移动到单独的区域以使用 UICloudSharingController 进行共享,如中所述https://developer.apple.com/wwdc21/10015
当用户停止共享时,我希望删除共享区域中的对象,并将其移回CoreData + CloudKit标准私有区域。使用以下方法删除 CKShare 及其区域:
/**
Delete the Core Data objects and the records in the CloudKit record zone associcated with the share.
*/
func purgeObjectsAndRecords(with share: CKShare, in persistentStore: NSPersistentStore? = nil) {
guard let store = (persistentStore ?? share.persistentStore) else {
print("\(#function): Failed to find the persistent store for share. \(share))")
return
}
persistentContainer.purgeObjectsAndRecordsInZone(with: share.recordID.zoneID, in: store) { (zoneID, error) in
if let error = error {
print("\(#function): …Run Code Online (Sandbox Code Playgroud) 我正在更新 iOS13 之前的 Core Data 应用程序,以使用 Core Data+CloudKit 同步来支持多个设备上的单个用户。同步应该自动发生,并且在我开发的中间步骤中它确实起作用了。现在它不起作用,CloudKit 遥测没有注册任何活动,我不明白为什么它不起作用。
在我以前的应用程序版本中,我在 UserDefaults 中提供了少量标签字符串,并允许用户修改它们,并将更新的版本放回 UserDefaults 中。这是避免为少量对象管理第二个核心数据实体的捷径。
我后来意识到这在多设备实现中不起作用,因为本地核心数据数据库为空这一事实不再意味着它是该用户的第一次使用。相反,每个新设备都需要查找基于云的数据源来查找用户正在使用的标签字符串,并且仅在用户没有其他内容时才使用应用程序提供的默认值。
我按照 Apple 的说明使用 CloudKit 设置核心数据,起初同步工作正常。但后来我意识到同步行为不正确,我真的需要提供一个预填充的核心数据数据库(.sqlite 文件),而不是从 UserDefaults 中存储的字符串进行预填充。我实现了这一点,并且在首次本地启动时复制捆绑的 .sqlite 文件后,该应用程序现在可以在本地正常运行。
但由于某种原因,此更改导致 CloudKit 同步停止工作。现在,我不仅在其他设备上没有获得任何自动更新,而且在 CloudKit 仪表板遥测中也没有得到任何结果,因此看来 CloudKit 同步从未开始。这很奇怪,因为我在本地收到刚刚在本地发生的“远程”更改的通知(当我在本地保存新数据时,我列为通知的 #selector 的函数正在本地调用)。
我对问题/解决方案是什么感到困惑。这是我的相关代码。
//In my CoreDataHelper class
lazy var context = persistentContainer.viewContext
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let appName = Bundle.main.infoDictionary!["CFBundleName"] as! String
let container = NSPersistentCloudKitContainer(name: appName)
//Pre-load my default Core Data data (Category names) on first launch
let storeUrl = FileManager.default.urls(for: .applicationSupportDirectory, …Run Code Online (Sandbox Code Playgroud) 所以我的问题正如标题中所写,如果您可以使用 NSPersistentCloudKitContainer 在不同应用程序之间共享数据,例如您有一个用于 iPad 的不同应用程序、一个用于 iPhone 的不同应用程序和一个用于 Mac 的不同应用程序,如果可能的话,您会怎么做?提前致谢!
核心数据是否可以处理简单的数据模型添加(例如新属性)而无需我提供任何进一步的“帮助”?就我而言,我有一个应用程序,它使用核心数据来处理与用户个人资料相关的各种事务。我有一个名为 Profile 的现有数据模型实体,我想向其中添加 2 个新属性:
hasPublished: Boolean
lastDetail: String
那么,这适用于我的情况吗?我没有重新命名任何东西,只是添加。
还要注意一点,我使用 NSPersistentCloudKitContainer 因为信息可以在用户设备之间共享。
data-migration core-data ios swift nspersistentcloudkitcontainer