检索更改的 CloudKit 条记录时识别记录更改的类型
Identify Type of Record Change when Retrieving Changed CloudKit Records
我正在尝试使用 CloudKit 同步和本地 CoreData 来完成一个应用程序。大多数操作都按预期工作,但我找不到确定 CloudKit 报告的更改类型的方法。我得到了更改的记录,但我需要知道更改是编辑、新记录还是删除。任何指导将不胜感激。
这是我认为可以配置为识别我需要对 CoreData 进行的编辑类型的代码片段。 Xcode10.2.1iOS12.2Swift(最新)
func fetchZoneChangesInZones( _ zones : [CKRecordZone.ID], _ completionHandler: @escaping (Error?) -> Void) {
var fetchConfigurations = [CKRecordZone.ID : CKFetchRecordZoneChangesOperation.ZoneConfiguration]()
for zone in zones {
if let changeToken = UserDefaults.standard.zoneChangeToken(forZone: zone) {
let configuration = CKFetchRecordZoneChangesOperation.ZoneConfiguration(previousServerChangeToken: changeToken, resultsLimit: nil, desiredKeys: nil)
fetchConfigurations[zone] = configuration
}//if let changeToken
}//for in
let operation = CKFetchRecordZoneChangesOperation(recordZoneIDs: zones, configurationsByRecordZoneID: fetchConfigurations)
operation.fetchAllChanges = true
var changedPatients = [CKRecord]()
var changedCategory1s = [CKRecord]()
//I thought that I should be able to query for the change type here and make separate arrays for each change type
operation.recordChangedBlock = { record in
if record.recordType == "Patient" {
changedPatients.append(record)
}
}//recordChangedBlock
operation.fetchRecordZoneChangesCompletionBlock = { [weak self] error in
for record in changedPatients {
//my actions here - need to choose new, changed or delete
self!.saveCKRecordToCoreData(record: record)
}//for record in
completionHandler(error)
}//fetchRecordZoneChangesCompletionBlock
operation.recordZoneFetchCompletionBlock = { recordZone, changeToken, data, moreComing, error in
UserDefaults.standard.set(changeToken, forZone: recordZone)
}//recordZoneFetchCompletionBlock
privateDatabase.add(operation)
}//fetchZoneChangesInZones
我在 swift 中表现不佳,但我会 post 在 objective c 中,因此您可以将其转换为 swift
首先,如果您想在记录被编辑、删除或创建时收到通知,您需要注册推送通知。
然后订阅更新将此块添加到 didFinishLaunchingWithOptions
- (void)subscribeToEventChanges
{
BOOL isSubscribed = [[NSUserDefaults standardUserDefaults] boolForKey:@"subscribedToUpdates"];
if (isSubscribed == NO) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
CKQuerySubscription *subscription = [[CKQuerySubscription alloc] initWithRecordType:@"Patient" predicate:predicate options:CKQuerySubscriptionOptionsFiresOnRecordCreation | CKQueryNotificationReasonRecordDeleted | CKQueryNotificationReasonRecordUpdated];
CKNotificationInfo *CKNotification=[[CKNotificationInfo alloc]init];
CKNotification.shouldSendContentAvailable=YES;
CKNotification.soundName=@"";
subscription.notificationInfo=CKNotification;
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:@"your container identifir"] privateCloudDatabase];
[publicDatabase saveSubscription:subscription completionHandler:^(CKSubscription * _Nullable subscription, NSError * _Nullable error) {
if (error) {
// Handle here the error
} else {
// Save that we have subscribed successfully to keep track and avoid trying to subscribe again
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"subscribedToUpdates"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
}
}
- 您将在
didReceiveRemoteNotification
中收到通知
这是一段代码
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
CKNotification *cloudKitNotification = [CKNotification notificationFromRemoteNotificationDictionary:userInfo];
if (cloudKitNotification.notificationType == CKNotificationTypeQuery) {
CKQueryNotification *queryNotification = (CKQueryNotification *)cloudKitNotification;
if (queryNotification.queryNotificationReason == CKQueryNotificationReasonRecordDeleted) {
// If the record has been deleted in CloudKit then delete the local copy here
} else {
// If the record has been created or changed, we fetch the data from CloudKit
CKDatabase *database;
if (queryNotification.databaseScope) {
database = [[CKContainer containerWithIdentifier:@"your container identifier"] privateCloudDatabase];
}
[database fetchRecordWithID:queryNotification.recordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {
if (error) {
// Handle the error here
} else {
if (queryNotification.queryNotificationReason == CKQueryNotificationReasonRecordUpdated) {
// Use the information in the record object to modify your local data
}else{
// Use the information in the record object to create a new local object
}
}
}];
}
}
}
该解决方案是针对正在使用的操作版本的单独方法。我已经收到通知,只是无法判断它们是更新、创建还是删除。只需在核心数据中搜索 recordName(这是一个 UUID)即可处理更新和创建。如果找到,则编辑,如果没有创建。问题是删除 - 使用 fetchRecordZoneChangesCompletionBlock 无法识别删除。但是,操作族有一个方法只是报告删除 - operation.recordWithIDWasDeletedBlock。我修改了之前的代码,添加了删除代码如下图
我的单一数据库订阅覆盖了整个私有数据库,因此没有必要订阅每个记录类型。
operation.fetchRecordZoneChangesCompletionBlock = { error in
for record in changedPatients {
//search for the record in coredata
if self.isSingleCoreDataRecord(ckRecord: record) {
//if found - then modify
self.saveUpdatedCloudKitRecordToCoreData(record: record)
} else {
//else add new
self.saveCKRecordToCoreData(record: record)
}
}//for record in
completionHandler(error)
}//fetchRecordZoneChangesCompletionBlock
operation.recordWithIDWasDeletedBlock = { (recordID, recordType) in
//delete the core data record here
let ckRecordToDelete = CKRecord(recordType: recordType, recordID: recordID)
self.removeOnePatientRecordFromCoreData(ckRecord: ckRecordToDelete)
}//recordWithIDWasDeletedBlock
我正在尝试使用 CloudKit 同步和本地 CoreData 来完成一个应用程序。大多数操作都按预期工作,但我找不到确定 CloudKit 报告的更改类型的方法。我得到了更改的记录,但我需要知道更改是编辑、新记录还是删除。任何指导将不胜感激。
这是我认为可以配置为识别我需要对 CoreData 进行的编辑类型的代码片段。 Xcode10.2.1iOS12.2Swift(最新)
func fetchZoneChangesInZones( _ zones : [CKRecordZone.ID], _ completionHandler: @escaping (Error?) -> Void) {
var fetchConfigurations = [CKRecordZone.ID : CKFetchRecordZoneChangesOperation.ZoneConfiguration]()
for zone in zones {
if let changeToken = UserDefaults.standard.zoneChangeToken(forZone: zone) {
let configuration = CKFetchRecordZoneChangesOperation.ZoneConfiguration(previousServerChangeToken: changeToken, resultsLimit: nil, desiredKeys: nil)
fetchConfigurations[zone] = configuration
}//if let changeToken
}//for in
let operation = CKFetchRecordZoneChangesOperation(recordZoneIDs: zones, configurationsByRecordZoneID: fetchConfigurations)
operation.fetchAllChanges = true
var changedPatients = [CKRecord]()
var changedCategory1s = [CKRecord]()
//I thought that I should be able to query for the change type here and make separate arrays for each change type
operation.recordChangedBlock = { record in
if record.recordType == "Patient" {
changedPatients.append(record)
}
}//recordChangedBlock
operation.fetchRecordZoneChangesCompletionBlock = { [weak self] error in
for record in changedPatients {
//my actions here - need to choose new, changed or delete
self!.saveCKRecordToCoreData(record: record)
}//for record in
completionHandler(error)
}//fetchRecordZoneChangesCompletionBlock
operation.recordZoneFetchCompletionBlock = { recordZone, changeToken, data, moreComing, error in
UserDefaults.standard.set(changeToken, forZone: recordZone)
}//recordZoneFetchCompletionBlock
privateDatabase.add(operation)
}//fetchZoneChangesInZones
我在 swift 中表现不佳,但我会 post 在 objective c 中,因此您可以将其转换为 swift
首先,如果您想在记录被编辑、删除或创建时收到通知,您需要注册推送通知。
然后订阅更新将此块添加到
didFinishLaunchingWithOptions
- (void)subscribeToEventChanges
{
BOOL isSubscribed = [[NSUserDefaults standardUserDefaults] boolForKey:@"subscribedToUpdates"];
if (isSubscribed == NO) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
CKQuerySubscription *subscription = [[CKQuerySubscription alloc] initWithRecordType:@"Patient" predicate:predicate options:CKQuerySubscriptionOptionsFiresOnRecordCreation | CKQueryNotificationReasonRecordDeleted | CKQueryNotificationReasonRecordUpdated];
CKNotificationInfo *CKNotification=[[CKNotificationInfo alloc]init];
CKNotification.shouldSendContentAvailable=YES;
CKNotification.soundName=@"";
subscription.notificationInfo=CKNotification;
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:@"your container identifir"] privateCloudDatabase];
[publicDatabase saveSubscription:subscription completionHandler:^(CKSubscription * _Nullable subscription, NSError * _Nullable error) {
if (error) {
// Handle here the error
} else {
// Save that we have subscribed successfully to keep track and avoid trying to subscribe again
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"subscribedToUpdates"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
}
}
- 您将在
didReceiveRemoteNotification
中收到通知
这是一段代码
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
CKNotification *cloudKitNotification = [CKNotification notificationFromRemoteNotificationDictionary:userInfo];
if (cloudKitNotification.notificationType == CKNotificationTypeQuery) {
CKQueryNotification *queryNotification = (CKQueryNotification *)cloudKitNotification;
if (queryNotification.queryNotificationReason == CKQueryNotificationReasonRecordDeleted) {
// If the record has been deleted in CloudKit then delete the local copy here
} else {
// If the record has been created or changed, we fetch the data from CloudKit
CKDatabase *database;
if (queryNotification.databaseScope) {
database = [[CKContainer containerWithIdentifier:@"your container identifier"] privateCloudDatabase];
}
[database fetchRecordWithID:queryNotification.recordID completionHandler:^(CKRecord * _Nullable record, NSError * _Nullable error) {
if (error) {
// Handle the error here
} else {
if (queryNotification.queryNotificationReason == CKQueryNotificationReasonRecordUpdated) {
// Use the information in the record object to modify your local data
}else{
// Use the information in the record object to create a new local object
}
}
}];
}
}
}
该解决方案是针对正在使用的操作版本的单独方法。我已经收到通知,只是无法判断它们是更新、创建还是删除。只需在核心数据中搜索 recordName(这是一个 UUID)即可处理更新和创建。如果找到,则编辑,如果没有创建。问题是删除 - 使用 fetchRecordZoneChangesCompletionBlock 无法识别删除。但是,操作族有一个方法只是报告删除 - operation.recordWithIDWasDeletedBlock。我修改了之前的代码,添加了删除代码如下图
我的单一数据库订阅覆盖了整个私有数据库,因此没有必要订阅每个记录类型。
operation.fetchRecordZoneChangesCompletionBlock = { error in
for record in changedPatients {
//search for the record in coredata
if self.isSingleCoreDataRecord(ckRecord: record) {
//if found - then modify
self.saveUpdatedCloudKitRecordToCoreData(record: record)
} else {
//else add new
self.saveCKRecordToCoreData(record: record)
}
}//for record in
completionHandler(error)
}//fetchRecordZoneChangesCompletionBlock
operation.recordWithIDWasDeletedBlock = { (recordID, recordType) in
//delete the core data record here
let ckRecordToDelete = CKRecord(recordType: recordType, recordID: recordID)
self.removeOnePatientRecordFromCoreData(ckRecord: ckRecordToDelete)
}//recordWithIDWasDeletedBlock