Как разрешить нескольким пользователям обновлять одну из моих записей 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
}
Другие вопросы по тегам