一段时间以来,我一直在尝试解决此问题,但无济于事。
从UserNotification定制操作访问托管对象,然后尝试将更改保存到该对象时,我收到以下消息:
[错误]错误:CoreData:错误:无法在NSManagedObject类'NSManagedObject'上调用指定的初始化程序。
基本上,设置如下:
1.用户收到通知
2.选择一个自定义动作
3.从通知中的信息中,UserNotification Center代表提取对象的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(实体:Intake; id:0x7fb1a9069e50 x-coredata:/// Intake / tAC4BBCD4-B128-4C6F-8E1B-2EE7D4EDBCB34;数据:故障)
当然,当调用函数时,会引发错误,但对象未正确初始化,而是将所有属性填充为nil
:
Home_Pillbox.HPBIntake:0x7fb1a9074e90(实体:Intake; id:0x7fb1a9069e50 x-coredata:/// Intake / tAC4BBCD4-B128-4C6F-8E1B-2EE7D4EDBCB34;数据:{剂量= 0;标识符=无; localNotification log =零;进餐= 0; medName =零; notificationRequest =零; profileName =零;日程表=零;状态= 1;治疗=零;单位= 0; userNotes =零;})
因此,当上下文尝试保存时,由于属性nil
而无法保存,这是数据模型所不允许的。令我困扰的是,即使对象输入正确,错误也会提到NSManagedObject
上指定的初始化程序,而不是子类HPBIntake
的名称。
任何帮助将不胜感激。
编辑:
这是DataController中saveContext()
函数的实现:
func saveContext() throws {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let syserr as NSError {
throw syserror
}
}
}
答案 0 :(得分:0)
一个主意:您说
如果我直接在应用中对此对象进行了相同的更改- 一切正常。
我假设您在主线程上进行了这些更改。
您是否检查过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
以及异常断点:
然后,当发生核心数据多线程冲突时,您的应用将停止。
答案 1 :(得分:0)
另一个想法:由于收到初始化错误,在我看来,当您尝试保存通过通知传递其ID的对象时,该对象尚未初始化。 在this link中,我发现了以下内容:
如果找不到该对象的记录,则object(with :)会引发异常。 它收到的对象标识符。例如,如果应用程序已删除 与对象标识符相对应的记录,核心数据为 无法提交您的应用程序相应的记录。结果 是一个例外。
existingObject(with :)方法的行为类似 时尚。主要区别在于,如果该方法抛出错误 无法获取与对象相对应的托管对象 标识符。
因此,我建议在getAssociatedObject(id: String)
中将对object(with: moid)
的调用替换为existingObject(with: moid)
。如果这引发了错误,则说明相关对象尚不存在或不再存在。
如果您的应用允许这样做,则必须由指定的初始化程序
init(entity entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?)
在尝试存储它之前。
编辑:
在this answer中,您可以找到有关调试核心数据处理的更多建议。