ios - 使用 CloudKit 在 iOS 11 中将通知标记为已读

标签 ios swift cloudkit nsnotification

我有一个使用 CloudKit 的应用程序,在 iOS 11 之前一切正常。

在以前的 iOS 版本中,我使用带有 NSPredicateCKQuerySubscription 来在用户更改特定表时接收通知,匹配 NSPredicate 属性.

这样做之后,每当服务器发送通知时,我都会遍历它们,获取它的更改,然后将它们标记为 READ,这样我会再次解析它们(保存 serverToken)。

现在在 iOS 11 中,Xcode 通知我这些委托(delegate)已已弃用,我应该更改它们,但这是我遇到问题的地方 - 我无法弄清楚如何在非弃用方式,适用于 iOS 11。

这是我的代码:

保存订阅

fileprivate func setupCloudkitSubscription() {
    let userDefaults = UserDefaults.standard
    let predicate = NSPredicate(format: /*...*/) // predicate here
    let subscription = CKQuerySubscription(recordType: "recordType", predicate: predicate, subscriptionID: "tablename-changes", options: [.firesOnRecordUpdate, .firesOnRecordCreation])
    let notificationInfo = CKNotificationInfo()
    notificationInfo.shouldSendContentAvailable = true // if true, then it will push as a silent notification
    subscription.notificationInfo = notificationInfo

    let publicDB = CKContainer.default().publicCloudDatabase
    publicDB.save(subscription) { (subscription, err) in
        if err != nil {
            print("Failed to save subscription:", err ?? "")
            return
        } 
    }       
}

检查未决通知

fileprivate func checkForPendingNotifications() {
    let serverToken = UserDefaults.standard.pushNotificationsChangeToken
    let operation = CKFetchNotificationChangesOperation(previousServerChangeToken: serverToken)

    var notificationIDsToMarkRead = [CKNotificationID]()
    operation.notificationChangedBlock = { (notification) -> Void in
        if let notificationID = notification.notificationID {
            notificationIDsToMarkRead.append(notificationID)
        }
    }
    operation.fetchNotificationChangesCompletionBlock = {(token, err) -> Void in
        if err != nil {
            print("Error occured fetchNotificationChangesCompletionBlock:", err ?? "")
            print("deleting existing token and refetch pending notifications")

            UserDefaults.standard.pushNotificationsChangeToken = nil
            return
        }
        let markOperation = CKMarkNotificationsReadOperation(notificationIDsToMarkRead: notificationIDsToMarkRead)
        markOperation.markNotificationsReadCompletionBlock  = { (notificationIDsMarkedRead: [CKNotificationID]?, operationError: Error?) -> Void in
            if operationError != nil {
                print("ERROR MARKING NOTIFICATIONS:", operationError ?? "")
                return
            }
        }
        let operationQueue = OperationQueue()
        operationQueue.addOperation(markOperation)
        if token != nil {
            UserDefaults.standard.pushNotificationsChangeToken = token
        }
    }
    let operationQueue = OperationQueue()
    operationQueue.addOperation(operation)
}

如您所见,上面的代码在 iOS 11 之前都能完美运行;

现在 Xcode 在以下几行提示警告:

let operation = CKFetchNotificationChangesOperation(previousServerChangeToken: serverToken)

警告:

'CKFetchNotificationChangesOperation' was deprecated in iOS 11.0: Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation

let markOperation = CKMarkNotificationsReadOperation(notificationIDsToMarkRead: notificationIDsToMarkRead)

警告:

'CKMarkNotificationsReadOperation' was deprecated in iOS 11.0: Instead of iterating notifications, consider using CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation as appropriate

我尝试应用 CKDatabaseSubscription 但这样做我无法像使用 CKQuerySubscription 那样应用 NSPredicate 来过滤订阅,如果我尝试获取并标记未决通知 作为 Read 它会显示这些警告。

在这种情况下,iOS 11 的最佳方法是什么?有什么提示吗?

谢谢。

最佳答案

正如我在上面的 openradar 错误报告中的评论中提到的那样,可以找到 here这是 iOS 11 中的一个已知问题,当获取公共(public)记录的更改并将这些更改标记为已读时,保存给定的 token 。

因为这个问题没有真正的解决方案,因为 Apple 没有为此提供解决方法,或者在给出解决方案之前可能不会将这些委托(delegate)功能标记为已弃用,我不得不走一条不同的道路,这是以下内容:

我必须在 Private Database 中创建一个自定义的 CKRecordZone,然后我必须通过这样做订阅该 zoneID 中的数据库更改,每当用户更改该数据库中的某些内容时,所需的 push-notifications 和/或 silent-push-notifications 都会按预期触发,然后我可以解析新数据。

我的问题是我在公共(public)数据库中有 User Profile,因此每当用户更改与他相关的内容(姓名、简历等)时,它就会保存在 CloudKit 中,并且会触发静默通知到用户的其他设备来更新这些数据——我也可以用私有(private)数据库完美地做到这一点——但我的问题是其他用户可以搜索应用程序用户来关注-取消关注他们,如果这些数据存储在私有(private)数据库中-数据库将超出一般用户搜索范围。

为了克服这个问题,我不得不半复制用户配置文件数据。 用户通过私有(private)数据库获取和编辑其数据,并在保存时同时更新公共(public)数据库中的半相关表,以便普通用户可以搜索。

直到 Apple 允许我们像以前在 iOS 10 中那样从公共(public)数据库中获取更改,此解决方案暂时对我有用。

关于ios - 使用 CloudKit 在 iOS 11 中将通知标记为已读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46908762/

相关文章:

ios - 快速将数据传递给委托(delegate)

ios - 管理 View Controller 以维护状态

ios - Datepicker maximumDate 在当天早​​些时候停留在昨天

ios - 获取静默推送通知

ios - 管理 CKQuerySubscriptions

ios - 如何使 NSDate 与关联对象一起工作?

ios - 如何防止在 Swift 中连续显示相同的随机颜色和随机事实?

ios - 上下滚动后 UITableViewCell 图像发生变化,但 TextLabel 文本保持不变(iOS8,Swift)

ios - 对于我的 iOS 笔记应用程序来说,这是包含文本、照片、音频和绘图笔记的最佳 iCloud 方法。我应该选择文档存储还是CloudKit?

ios - 如何在 iOS 9 的 Swift 2 中调用 CloudKit 中的完成 block ?