通过UserNotification自定义操作访问时,CoreData无法初始化托管对象

问题描述 投票:0回答:2

我一直试图解决这个问题一段时间,但无济于事。 从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
            }
        }
    }
ios swift core-data
2个回答
0
投票

还有一个想法:由于您收到初始化程序错误,在我看来,当您尝试保存时,通过通知传输的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中,您可以找到有关如何调试核心数据处理的更多建议。


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以及异常断点: enter image description here然后,当发生核心数据多线程违规时,您的应用程序将停止。

© www.soinside.com 2019 - 2024. All rights reserved.