I've been trying to solve this problem for some time, to no avail.
When accessing a managed object from UserNotification custom action and then trying to save the changes to this object I get the following message:
[error] error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'NSManagedObject'.
Basically, the setup is as follows:
1. User gets a notification
2. Chooses a custom action
3. From the info in the notification the UserNotification Center Delegate extracts the URI of the object and then extracts it from the persistent store
4. Once done and type-casted the delegate calls appropriate method on the object
5. After method returns delegate tries to save the context, and that's where the error appears.
Here is some relevant code:
// - 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()
}
The function to extract an object from persistent store:
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)
}
If I make the same changes on this object directly in the app - everything works. So I assume the matter is with getting the object from a custom action on User Notification. But I can't figure out what is the problem.
Here is some additional info. When I inspect the reminder
object right before calling the take(on:)
function, it shows as a fault:
Home_Pillbox.HPBIntake: 0x7fb1a9074e90 (entity: Intake; id: 0x7fb1a9069e50 x-coredata:///Intake/tAC4BBCD4-B128-4C6F-8E1B-2EE7D4EDBCB34 ; data: fault)
Of course, when the function is called, the fault is fired but the object is not initialised correctly and instead populates all properties as nil
:
Home_Pillbox.HPBIntake: 0x7fb1a9074e90 (entity: Intake; id: 0x7fb1a9069e50 x-coredata:///Intake/tAC4BBCD4-B128-4C6F-8E1B-2EE7D4EDBCB34 ; data: {dosage = 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;})
So when the context tries to save it can't, as properties are nil
, which is not allowed by the data model. What also bothers me is that the error mentions designated initialiser on NSManagedObject
instead of the name of the subclass HPBIntake
, even though the object is clearly correctly typed.
Any help will be highly appreciated.
EDIT:
Here's the implementation of saveContext()
function in the DataController:
func saveContext() throws {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let syserr as NSError {
throw syserror
}
}
}