iOS 8:通过订阅收到CKRecord更改通知

时间:2014-07-14 23:46:54

标签: swift ios8 cloudkit

我正在运行CKFetchNotificationChangesOperation以下拉自上次我的应用运行以来应该发送的所有更新通知。

我得到了一堆CKNotification个对象,正如我所期望的那样,但每个CKNotification的recordFields对象都是零。我希望它可以填充我对象的所有已更改属性。 但也许情况并非如此。

我没有指定desiredKeys对象的CKSubscription属性,这显然会强制CKNotification recordFields保存该数据。但是文档说desiredKeys只能有3个值,而且我的对象有3个以上可以更新的值。

所以现在我在想,我只需要获取CKNotification对象,看看它是否是更新,然后重新获取它指向的对象以检索其数据。然后,我可以对新CKRecord与旧版本进行差异,看看有什么变化。

我是否正确理解了这一点?

2 个答案:

答案 0 :(得分:3)

首先,您需要存储CKServerChangeToken

提供的CKFetchNotificationChangesOperation
var notificationChangesOperation = CKFetchNotificationChangesOperation(previousServerChangeToken: previousChangeToken)

var fetchedRecordIDs:[CKRecordID]()

//we just care about inserts, we don't care about of changes of records existing in database, that's why it's enough just to save recordIDs
notificationChangesOperation.notificationChangedBlock = {notification in

    let queryNotif = notification as CKQueryNotification
    //            println("fetched  CKQueryNotification \(queryNotif)")

    if (!contains(fetchedRecordIDs, queryNotif.recordID)) {
        fetchedRecordIDs.append(queryNotif.recordID)
    }
}

notificationChangesOperation.fetchNotificationChangesCompletionBlock = {serverChangeToken, error in
    if (error) {
        println("failed to fetch notification \(error)")
    }

    self.previousChangeToken = serverChangeToken

    completionHandler(recordIDs: fetchedRecordIDs, error: error)
}

container.addOperation(notificationChangesOperation)

var previousChangeToken:CKServerChangeToken? {
    get {
        let encodedObjectData = NSUserDefaults.standardUserDefaults().objectForKey(SubscriptionKeys.PreviousChangeToken) as? NSData

        if (encodedObjectData) {
            return NSKeyedUnarchiver.unarchiveObjectWithData(encodedObjectData) as? CKServerChangeToken
        }

        return nil
    }
    set(newToken) {
        if (newToken) {
            println("new token \(newToken)")

            NSUserDefaults.standardUserDefaults().setObject(NSKeyedArchiver.archivedDataWithRootObject(newToken), forKey:SubscriptionKeys.PreviousChangeToken)
        }
    }
}

然后在CKFetchNotificationChangesOperation的下一次调用中传递它。然后,此操作将为您提供自上次请求以来的更新。 CKNotificationCKQueryNotification)为您提供CKRecordID个对象,而不是CKRecord

因此,您需要使用CKRecord重新获取这些ID的所有CKFetchRecordsOperation,并相应地更新模型对象。

func queryMessagesWithIDs(IDs:[CKRecordID], completionHandler: ([CKRecord]!, NSError!) -> Void) {
    var fetchRecordsOperation = CKFetchRecordsOperation(recordIDs: IDs)

    var messages:[CKRecord]()

    fetchRecordsOperation.perRecordCompletionBlock = {record, recordID, error in
        if (!error) {
            messages.append(record)
        } else {
            println("failed to get message with ID \(recordID.recordName)")
        }
    }

    fetchRecordsOperation.fetchRecordsCompletionBlock = {_, error in
        if (error) {
            println(error)
        } else {
            messages.sort{$0.creationDate.compare($1.creationDate) == NSComparisonResult.OrderedAscending}
        }

        dispatch_async(dispatch_get_main_queue(), {completionHandler(messages, error)})
    }

    publicDatabase.addOperation(fetchRecordsOperation)
}

答案 1 :(得分:1)

在iOS 11中,不推荐使用CKFetchNotificationChangesOperation,标题为Apple建议:

"使用CKDatabaseSubscription,CKFetchDatabaseChangesOperation和CKFetchRecordZoneChangesOperation"

,而不是迭代通知以枚举更改的记录区域。