Как разрешить нескольким пользователям обновлять одну из моих записей CloudKit одновременно, не перекрывая друг друга?
У меня есть кнопка "Мне нравится", и все пользователи используют ее одновременно. Следует увеличить значение аналогичной записи в облачном контейнере на единицу или уменьшить его на единицу. Как я могу гарантировать, что обновление произойдет с последней версией записи? Я имею в виду, что это за код в Swift 3, который может гарантировать, что каждый пользователь получит окончательное значение аналогичной записи и применит приращение, в то время как другие пользователи отправят ту же операцию для той же записи? Извините, у меня нет кода, чтобы показать об этом.
Я читаю о CKErrorServerRecordChanged
но я не знаю, как использовать его в синтаксисе. Если у вас есть пример для кода будет, это будет здорово.
Я нашел это в Firebase. Он называется транзакцией и отслеживает версию записи, пока не применяет операцию к последней версии, поэтому он не потеряет ни одну пользовательскую операцию, нацеленную на эту запись.
1 ответ
Хорошо, не уверен, что это ответ "вырезать и вставить", но даст вам шаблон для работы. Он показывает расширенную обработку кода ошибки, например, действие рядом с повторной попыткой с действием сохранения. Вы должны научиться делать то, что вы хотите делать с этим кодом.
func files_saveSet() {
let newRecord = CKRecord(recordType: "Blah", recordID: sharedDataAccess.iCloudID)
newRecord["Key"] = sharedDataAccess.iCloudLink as CKRecordValue?
var localChanges:[CKRecord] = []
let records2Erase:[CKRecordID] = []
localChanges.append(newRecord)
let saveRecordsOperation = CKModifyRecordsOperation(recordsToSave: localChanges, recordIDsToDelete: records2Erase)
saveRecordsOperation.savePolicy = .changedKeys
saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
self.theApp.isNetworkActivityIndicatorVisible = false
guard error == nil else {
if let ckerror = error as? CKError {
if ckerror.code == CKError.requestRateLimited {
let retryInterval = ckerror.userInfo[CKErrorRetryAfterKey] as? TimeInterval
DispatchQueue.main.async {
Timer.scheduledTimer(timeInterval: retryInterval!, target: self, selector: #selector(self.files_saveSet), userInfo: nil, repeats: false)
}
} else if ckerror.code == CKError.zoneBusy {
let retryInterval = ckerror.userInfo[CKErrorRetryAfterKey] as? TimeInterval
DispatchQueue.main.async {
Timer.scheduledTimer(timeInterval: retryInterval!, target: self, selector: #selector(self.files_saveSet), userInfo: nil, repeats: false)
}
} else if ckerror.code == CKError.limitExceeded {
let retryInterval = ckerror.userInfo[CKErrorRetryAfterKey] as? TimeInterval
DispatchQueue.main.async {
Timer.scheduledTimer(timeInterval: retryInterval!, target: self, selector: #selector(self.files_saveSet), userInfo: nil, repeats: false)
}
} else if ckerror.code == CKError.notAuthenticated {
NotificationCenter.default.post(name: Notification.Name("noCloud"), object: nil, userInfo: nil)
} else if ckerror.code == CKError.networkFailure {
NotificationCenter.default.post(name: Notification.Name("networkFailure"), object: nil, userInfo: nil)
} else if ckerror.code == CKError.networkUnavailable {
NotificationCenter.default.post(name: Notification.Name("noWiFi"), object: nil, userInfo: nil)
} else if ckerror.code == CKError.quotaExceeded {
NotificationCenter.default.post(name: Notification.Name("quotaExceeded"), object: nil, userInfo: nil)
} else if ckerror.code == CKError.partialFailure {
NotificationCenter.default.post(name: Notification.Name("partialFailure"), object: nil, userInfo: nil)
} else if (ckerror.code == CKError.internalError || ckerror.code == CKError.serviceUnavailable) {
NotificationCenter.default.post(name: Notification.Name("serviceUnavailable"), object: nil, userInfo: nil)
}
} // end of guard statement
return
}
if error != nil {
//print(error!.localizedDescription)
} else {
//print("ok")
}
}
saveRecordsOperation.qualityOfService = .background
privateDB.add(saveRecordsOperation)
theApp.isNetworkActivityIndicatorVisible = true
}