CKQueryNotification.recordID: нераспознанный селектор отправлен в экземпляр

Я пытаюсь настроить тихие push-уведомления для распространения локальных уведомлений на устройства с помощью CloudKit, и я не могу понять, почему мое приложение вылетает каждый раз, когда я получаю удаленное уведомление.

Все работает нормально, пока я не попытаюсь обработать полученное уведомление. Сбой происходит при попытке доступа к идентификатору записи для объекта CKQueryNotification внутри didReceiveRemoteNotification.

Я регистрируюсь для удаленных уведомлений внутри приложения didFinishLaunchingWithOptions. А это остальная часть кода:

Внутри didRegisterForRemoteNotification я создаю CKSubscription для типа записи CD_Task.

   func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

        let subscription = CKQuerySubscription(recordType: "CD_Task", predicate: NSPredicate(format: "TRUEPREDICATE"), options: .firesOnRecordCreation)

        let info = CKSubscription.NotificationInfo()            
        subscription.notificationInfo = info

        CKContainer.default().privateCloudDatabase.save(subscription, completionHandler: { subscription, error in
            if error == nil {
                // Subscription saved successfully
            } else {
                // Error occurred, handle it
            }
        })
    }

Внутри DidReceiveRemoteNotification я передаю объект CKQueryNotification функции для обработки удаленного уведомления, полученного от iCloud:

   func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if let ckqn = CKQueryNotification(fromRemoteNotificationDictionary: userInfo as! [String:NSObject]) {
            self.iCloudHandleNotification(ckqn)
        }
    }

Наконец, вот код функции iCloudHandleNotification:

        func iCloudHandleNotification(_ ckqn: CKQueryNotification) {
                    switch ckqn.queryNotificationReason {
                    case .recordCreated:
                        // This is where it crashes.. when I try to access ckqn.recordID
                        CKContainer.default().privateCloudDatabase.fetch(withRecordID: ckqn.recordID!) { (record, error) in
                            if let record = record {
                                // Handle creating local notif for record
                            } else if let error = error {
                                print("Unable to retrieve record: \(error)")
                            }
                        }
                    default:
                        break
                 }
        }

РЕДАКТИРОВАТЬ:

После расследования мне кажется, что я получаю CKDatabaseNotification вместо CKQueryNotification - как я могу указать, что мне нужен CKQueryNotification?

1 ответ

Решение

Я наконец-то понял. Я использую NSPersistentCloudKitContainer для синхронизации данных между устройствами. Моя подписка отслеживала любые изменения, внесенные в запись, созданную NSPersistentCloudKitContainer, поэтому каждый раз при внесении изменений она создавала CKDatabaseNotification вместо CKQueryNotification. Поскольку я пытался обработать CKQueryNotification, мое приложение продолжало аварийно завершать работу, так как оно не могло найти идентификатор записи, следовательно, сообщение об ошибке.

Чтобы решить эту проблему, я создал отдельную запись (не часть NSPersistentCloudKitContainer) в iCloud и заставил мою подписку CKSubscription наблюдать за любыми изменениями в этой записи.