我正在运行一个CKFetchNotificationChangesOperation来下载所有的更新通知,这些通知应该是从我的应用程序上次运行以来发送的。
正如我所期望的,我得到了一堆CKNotification对象,但是每个CKNotification的recordFields对象都是空的。我希望它会填充我的对象的所有更改的属性。但也许事实并非如此。
我没有指定CKSubscription对象的desiredKeys属性,这显然会强制CKNotification recordFields保存该数据。但是文档说desiredKeys只能有3个值,而我的对象有比3个值多得多的值可以更新。
所以现在我想,我只需要获取CKNotification对象,看看它是否是更新,然后重新获取它所指向的对象来检索它的数据。然后,我可以对新的CKRecord和旧的进行比较,看看有什么变化。
我的理解正确吗?
发布于 2014-07-20 11:53:23
首先,您需要存储CKFetchNotificationChangesOperation提供的CKServerChangeToken
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的下一个调用中传递它。则此操作将为您提供自上次请求以来的更新。CKNotification (CKQueryNotification)为您提供CKRecordID对象,而不是CKRecord。
因此,您需要使用CKFetchRecordsOperation重新获取这些ID的所有CKRecord,并相应地更新模型对象。
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)
}发布于 2015-04-18 17:59:30
iOS 11中弃用了CKFetchNotificationChangesOperation,在标题中苹果建议:
使用CKDatabaseSubscription、CKFetchDatabaseChangesOperation和CKFetchRecordZoneChangesOperation,而不是通过迭代通知来枚举已更改的记录区
https://stackoverflow.com/questions/24747799
复制相似问题