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 наблюдать за любыми изменениями в этой записи.