Почему мы включаем функцию постоянного отслеживания истории?< /h2>
Из-за проблемы, описанной в https://stackoverflow.com/a/72554542/72437, нам необходимо включить NSPersistentHistoryTrackingKey.
Очистить историю
На основании https://developer.apple.com/documentati ... re_changes, мы должны выполнить постоянную очистку истории вручную.< /p>
Но не совсем ясно, как мы можем очистить историю безопасным способом, не влияя на корректность CloudKit. Мы обычно проводим несколько тестов со следующей настройкой.
- Запустите симулятор. Мы выполним операцию вставки в симуляторе.
- Запустите реальное устройство. Реальное устройство получит автоматическое push-уведомление на этапе 1.
- И симулятор, и реальное устройство выполняют один и тот же код.
- Каждый раз, когда мы вставьте элемент в симулятор, и мы посмотрим, что произойдет на реальном устройстве.
Код: Выделить всё
@objc func storeRemoteChange(_ notification: Notification) {
// Process persistent history to merge changes from other coordinators.
historyQueue.addOperation {
self.processPersistentHistory()
}
}
/**
Process persistent history, posting any relevant transactions to the current view.
*/
private func processPersistentHistory() {
backgroundContext.performAndWait {
// Fetch history received from outside the app since the last token
let historyFetchRequest = NSPersistentHistoryTransaction.fetchRequest!
historyFetchRequest.predicate = NSPredicate(format: "author != %@", appTransactionAuthorName)
let request = NSPersistentHistoryChangeRequest.fetchHistory(after: lastHistoryToken)
request.fetchRequest = historyFetchRequest
let result = (try? backgroundContext.execute(request)) as? NSPersistentHistoryResult
guard let transactions = result?.result as? [NSPersistentHistoryTransaction] else { return }
...
// Update the history token using the last transaction.
lastHistoryToken = transactions.last!.token
// Remove history before the last history token
let purgeHistoryRequest = NSPersistentHistoryChangeRequest.deleteHistory(before: lastHistoryToken)
do {
try backgroundContext.execute(purgeHistoryRequest)
} catch {
error_log(error)
}
}
}
Наша гипотеза по поводу этой проблемы:
- Данные истории персистентности распределяются между несколькими координаторами персистентности.
- Наш видимый координатор завершил обработку транзакции, отметьте запись в LastHistoryToken, а затем очистите все истории старше, чем LastHistoryToken< /code>.
- Однако существует еще один невидимый координатор, используемый CloudKit для синхронизации. Существует высокая вероятность того, что координатор CloudKit еще не обработал удаленные транзакции истории.
- Это приводит к тому, что все данные становятся неправильными, когда CloudKit пытается синхронизировать данные реального устройства без необходимой истории транзакций.
Мы настраиваем приведенный выше код, удаляя только историю транзакций старше 2 минут.
Код: Выделить всё
// Remove history older than 2 minutes.
let date = Date(timeMillis: Date.currentTimeMillis - 2*60*1000)
let purgeHistoryRequest = NSPersistentHistoryChangeRequest.deleteHistory(before: date)
do {
try backgroundContext.execute(purgeHistoryRequest)
} catch {
error_log(error)
}
- Если разница во времени между последним срабатыванием storeRemoteChange и текущим срабатыванием storeRemoteChange< /code> меньше 2 минут, реальное устройство получит правильную информацию о синхронизации CloudKit.
- Если разница во времени между последним срабатыванием storeRemoteChange и текущий storeRemoteChange превышает 2 минуты, реальное устройство получит неправильную информацию для синхронизации CloudKit. Реальное устройство либо получает дублированные данные, либо его данные удаляются.
На основе статьи «Как сократить историю прямо в приложении CoreData+CloudKit?»
Предлагает автор
Поэтому действительно безопасно удалять постоянную историю, скажем, через семь
дней после ее обработки.
Для 1 пользователя: Корпус для 2 устройств.
- Пользователь часто читает/пишет на своем часто используемом устройстве A.
- пользователь запустит то же приложение на своем редко используемом устройстве Б через 7 дней с момента последнего использования на устройстве Б.
Если да, то каков хороший способ выполнить постоянную очистку истории, не влияя на корректность CloudKit?
Как запустить тест 2?
Вы можете настроить и запустить тест 2
- Настройте и запустите пример из https://developer.apple.com/documentati ... _the_cloud
- Замените CoreDataStack.swift на https: //gist.github.com/yccheok/df21f199b81b19764ffbcd4a4583c430. Он содержит вспомогательные функции для даты и код очистки двухминутной истории.
- В симуляторе создайте 1 записи, коснувшись верхнего правого угла. Вы можете видеть, что на реальном устройстве теперь есть 1 записей.
- Через 3 минуты снова нажмите в правом верхнем углу. В симуляторе вы можете увидеть всего 2 записи. Однако на реальном устройстве данные исчезли!
(На этом рисунке левое устройство — настоящее устройство, а правое — симулятор)
Подробнее здесь: https://stackoverflow.com/questions/725 ... ffecting-t