Core data NSPersistentStoreRemoteChangeNotification未被激发
我正在尝试在我的CoreData+CloudKit项目中执行历史记录跟踪,该项目使用Core data NSPersistentStoreRemoteChangeNotification未被激发,core-data,cloudkit,ios13,nspersistentcloudkitcontainer,Core Data,Cloudkit,Ios13,Nspersistentcloudkitcontainer,我正在尝试在我的CoreData+CloudKit项目中执行历史记录跟踪,该项目使用NSPersistentCloudKitContainer。我一直在追随苹果的脚步 我想在远程存储更新后执行某些任务。为此,苹果建议在应用程序的签名和功能的后台模式部分启用远程通知 我已经为我的项目启用了历史记录跟踪,如Apple的示例项目所示 // turn on persistent history tracking let description = container.persistent
NSPersistentCloudKitContainer
。我一直在追随苹果的脚步
我想在远程存储更新后执行某些任务。为此,苹果建议在应用程序的签名和功能的后台模式部分启用远程通知
我已经为我的项目启用了历史记录跟踪,如Apple的示例项目所示
// turn on persistent history tracking
let description = container.persistentStoreDescriptions.first
description?.setOption(true as NSNumber,
forKey: NSPersistentHistoryTrackingKey)
// ...
我还注册了我的商店,以监听商店的变化
// turn on remote change notifications
let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey"
description?.setOption(true as NSNumber,
forKey: remoteChangeKey)
// ...
还添加了观察者以侦听NSPersistentStoreRemoteChangeNotification
但是,没有触发NSPersistentStoreRemoteChangeNotification
。为了确保我的实现没有错误,我只是在苹果提供的示例代码@objc func storeRemoteChange(u-notification:notification)
中设置了断点,但我仍然看不到任何通知被触发,也没有断点被激活
我已经了解了在示例项目中完成的标记重复数据消除,并尝试过对其进行测试,但没有任何成功。这是苹果实现中的一个bug还是我缺少了任何必要的设置?调试OP提到的示例应用程序时,我观察到以下几点:
- 从XCode版本11.3(11C29)开始,选项键(
)和通知名称(NSPersistentStoreRemoteChangeNotificationPostOptionKey
)都有SDK常量,这些常量反映在最新下载的示例代码中.NSPersistentStoreRemoteChange
- 示例应用程序在错误的对象上注册远程更改通知,因此它从未收到任何更改通知。根据接受的答案更改发件人可以解决此问题
- 应用程序UI始终会更新以反映从云收到的更改,但这些更新不是由远程更改通知提示的,而是由应用程序的
委托使用NSFetchedResultsController
回调刷新UI提示的controllerdChangeContent
- 示例应用程序使用的标准
正在将所有云发送的更新自动导入到本地永久存储中,因为persistentStore设置为历史跟踪,viewContext设置为自动更新到最新一代数据,每次导入都会触发UI更新NSPersistentCloudKitContainer
@FetchRequest
包装器在主视图显示中获取数据。果然,在不使用任何远程更改通知的情况下,我看到了完全相同的远程导入行为,并且每次导入后都会更新UI
然后,我确认,根据接受的答案,如果我正确注册远程更改通知,它们将被接收。它们似乎是在NSPersistentCloudKit中的每个接收和导入操作完成后发送的。不需要观察它们来获取由这些导入启动的本地数据更改的通知。我猜您是在观察容器而不是商店协调员,请按如下方式添加您的观察者:
NotificationCenter.default.addObserver(
self, selector: #selector(type(of: self).storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
注意最后一个参数container.persistentStoreCoordinator
还有一个警告,此通知会出现在所有不同的线程上,因此您要小心并发性。只需在方法中放置5秒睡眠,您将在应用程序启动时看到3个不同的线程调用它。这可能就是为什么在示例中有一个historyQueue
和maxOperationCount
1来处理它
有些通知在
userInfo
中有NSPersistentHistoryTokenKey
,不知道原因。我不知道这是否是一个bug。只需下载并运行苹果的示例项目,但永远不会触发NSPersistentStoreRemoteChangeNotification
我在AppDelegate中为相同的NSPersistentStoreRemoteChangeNotification
添加了一个观察者,它正在启动
我在AppDelegate中添加了通知观察者,然后只需调用CoreDataStack的StoreRemoteChange(:)
。此外,标记重复数据消除逻辑工作正常
下面是我在AppDelegate中添加的代码
func应用程序(application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.launchOptions键:任意])->Bool{
//视图控制器层次结构在主情节提要中定义。
guard let splitViewController=window?.rootViewController作为UISplitViewController,
将navController=splitViewController.ViewController[splitViewController.ViewController.count-1]设为?UINavigationController,
让topViewController=navController.topViewController{
返回错误
}
//配置splitViewController。
topViewController.navigationItem.leftBarButtonItem=splitViewController.displayModeButtonItem
splitViewController.delegate=self
splitViewController.preferredDisplayMode=.allVisible
//观察核心数据远程更改通知。
NotificationCenter.default.addObserver(
self,selector:#selector(类型(of:self).storeRemoteChange(35;:),
名称:.NSPersistentStoreRemoteChange,对象:nil)
返回真值
}
@objc
func storeRemoteChange(uu通知:通知){
coreDataStack.storeRemoteChange(通知)
}
我能够通过iCloud在我的项目中的两台设备之间可靠地回显核心数据更改。但我已经到了需要了解变革历史的地步。苹果已经很好地描述了在中设置它的步骤
我跟着
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentCloudKitContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentCloudKitContainer(name: "yourProjectNameGoesHere")
// turn on persistent history tracking
// https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes
let description = container.persistentStoreDescriptions.first
description?.setOption(true as NSNumber,
forKey: NSPersistentHistoryTrackingKey)
// turn on remote change notifications
let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey"
description?.setOption(true as NSNumber,
forKey: remoteChangeKey)
// this will make background updates from iCloud available to the context.
container.viewContext.automaticallyMergesChangesFromParent = true
// call this LAST, after the persistentStoreDescriptions configuration.
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
init() {
NotificationCenter.default.addObserver(self,
selector: #selector(fetchChanges),
name: .NSPersistentStoreRemoteChange,
object: pc.persistentStoreCoordinator)
}
@objc func fetchChanges(note: Notification) {
print("Just received a NSPersistentStoreRemoteChange notification")
}