通过UserNotification自定义操作访问时,CoreData无法初始化托管对象
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过UserNotification自定义操作访问时,CoreData无法初始化托管对象相关的知识,希望对你有一定的参考价值。
我一直试图解决这个问题一段时间,但无济于事。 从UserNotification自定义操作访问托管对象,然后尝试将更改保存到此对象时,我收到以下消息:
[error]错误:CoreData:错误:无法在NSManagedObject类'NSManagedObject'上调用指定的初始值设定项。
基本上,设置如下: 1.用户收到通知 2.选择自定义操作 3.从通知中的信息中,UserNotification Center Delegate提取对象的URI,然后从持久性存储中提取它 4.完成并输入类型后,委托会在对象上调用适当的方法 5.方法返回后,委托尝试保存上下文,这就是错误出现的位置。
这是一些相关的代码:
// - UNUserNotification Centre delegate
extension HPBUserNotificationsHandler: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
guard let object = getAssociatedObject(id: response.notification.request.identifier) else { return }
switch response.actionIdentifier {
case UNNotificationDismissActionIdentifier:
....
case UNNotificationDefaultActionIdentifier:
....
case HPBReminderAction.take.rawValue:
// get intake object
guard let reminder = object as? HPBIntake else { return }
reminder.take(at: Date())
try! dataController.saveContext() // here is when the error is raised
default:
break
}
completionHandler()
}
从持久性存储中提取对象的函数:
func getAssociatedObject(id: String) -> NSManagedObject? {
guard let psc = dataController.managedObjectContext.persistentStoreCoordinator else { return nil }
guard let objURL = URL(string: id) else { return nil }
guard let moid = psc.managedObjectID(forURIRepresentation: objURL) else { return nil }
return dataController.managedObjectContext.object(with: moid)
}
如果我直接在应用程序中对此对象进行相同的更改 - 一切正常。所以我假设问题是从用户通知的自定义操作中获取对象。但我无法弄清楚问题是什么。
这是一些额外的信息。当我在调用reminder
函数之前检查take(on:)
对象时,它显示为错误:
Home_Pillbox.HPBIntake:0x7fb1a9074e90(entity:Intake; id:0x7fb1a9069e50 x-coredata:/// Intake / tAC4BBCD4-B128-4C6F-8E1B-2EE7D4EDBCB34; data:fault)
当然,在调用函数时,会触发错误但是对象未正确初始化,而是将所有属性填充为nil
:
Home_Pillbox.HPBIntake:0x7fb1a9074e90(entity:Intake; id:0x7fb1a9069e50 x-coredata:/// Intake / tAC4BBCD4-B128-4C6F-8E1B-2EE7D4EDBCB34; data:{dose = 0; identifier = nil; localNotification = nil; log = nil ; meal = 0; medName = nil; notificationRequest = nil; profileName = nil; schedule = nil; status = 1; treatment = nil; unit = 0; userNotes = nil;})
因此,当上下文尝试保存时,它不能,因为属性是nil
,这是数据模型不允许的。令我困扰的是错误提到NSManagedObject
上的指定初始化器而不是子类HPBIntake
的名称,即使该对象显然是正确键入的。
任何帮助将受到高度赞赏。
编辑:这是在DataController中实现saveContext()
函数:
func saveContext() throws {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let syserr as NSError {
throw syserror
}
}
}
还有一个想法:由于您收到初始化程序错误,在我看来,当您尝试保存时,通过通知传输的ID尚未初始化。 在this link,我发现了以下内容:
如果找不到它收到的对象标识符的记录,则object(with :)会抛出异常。例如,如果应用程序删除了与对象标识符对应的记录,则Core Data无法将您的应用程序交给相应的记录。结果是一个例外。 existingObject(with :)方法的行为方式类似。主要区别在于,如果无法获取与对象标识符对应的托管对象,则该方法会抛出错误。
所以我建议用getAssociatedObject(id: String)
替换object(with: moid)
对existingObject(with: moid)
的调用。如果这会引发错误,则表示相关对象尚未存在或不存在。
如果您的应用允许此操作,则必须使用指定的初始化程序对其进行初始化
init(entity entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?)
在你尝试存储它之前。
编辑:
在this answer中,您可以找到有关如何调试核心数据处理的更多建议。
只是一个想法:你说
如果我直接在应用程序中对此对象进行相同的更改 - 一切正常。
我假设您在主线程上进行了这些更改。
你有没有检查userNotificationCenter(_:didReceive:withCompletionHandler:)
是否也在主线程上执行了?如果没有,那么您可能会遇到问题,因为核心数据只能在一个线程上执行。在这种情况下,您可以尝试执行此函数的主体
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
DispatchQueue.main.async {
// Your code here
}
}
您还应该在方案中设置启动参数-com.apple.CoreData.ConcurrencyDebug 1
以及异常断点:
然后,当发生核心数据多线程违规时,您的应用程序将停止。
以上是关于通过UserNotification自定义操作访问时,CoreData无法初始化托管对象的主要内容,如果未能解决你的问题,请参考以下文章
Windows 安装程序,在 C++ 中访问自定义操作中的自定义属性
什么是 UserNotification 框架相当于 didReceive 通知:UILocalNotification?