Как создать снимок состояния CoreData? - PullRequest
0 голосов
/ 04 января 2019

Фоновая история

Я занимаюсь разработкой большого приложения для iOS. Это приложение работает при определенных допущениях. Основным из них является то, что приложение должно работать автономно с внутренним хранилищем, которое является снимком последнего синхронизированного состояния данных, сохраненных на сервере. Я решил использовать CoreData для обработки этого хранилища. Каждый раз, когда приложение запускается, я проверяю, включено ли соединение WiFi, и затем пытаюсь синхронизировать хранилище с сервером. Синхронизация может занять около 3 минут из-за размера данных.

Процесс синхронизации состоит из нескольких этапов, и на каждом из них I:

  • получить некоторые данные с сервера (XML)
  • десериализовать его
  • сохранить в Core Data

Задача

Процесс синхронизации может быть прерван по нескольким причинам (подключение к Интернету, отключение сервера, выход пользователя из приложения и т. Д.). Это может привести к несинхронизации данных.

Предположим, что процесс синхронизации состоит из 5 этапов и прерывается после третьего. Это приводит к тому, что 3/5 данных обновляются во внутреннем хранилище, а остальные не синхронизированы. Я не могу этого допустить, потому что данные тесно связаны друг с другом (бизнес-логика).

Цель

Я не знаю, возможно ли это, но я думаю о реализации одного решения. При запуске процесса синхронизации я хотел бы создать моментальный снимок (своего рода копию) текущего состояния Core Date и в процессе работы с ним над ним. Когда процесс синхронизации завершается успешно, этот снимок может перезаписать текущее состояние CoreData. Когда синхронизация прерывается, снимок может быть просто отменен. Мое внутреннее хранилище будет защищено.

Вопросы

  • Как создать снимок CoreData?
  • Как работать со снимком CoreData?
  • Как перезаписать состояние CoreDate со снимком?

Спасибо в совете за любую помощь. Примеры кода, если это возможно, будут оценены.

РЕДАКТИРОВАТЬ 1

Размер данных слишком велик, чтобы обрабатывать его в нескольких контекстах CoreData. Во время синхронизации я несколько раз сохраняю текущий контекст для очистки памяти. Если я этого не сделаю, приложение завершится с ошибкой памяти.

Я думаю, что это должно быть разрешено несколькими NSPersistentStoreCoordinator с использованием, например, этого метода: link . К сожалению, я не знаю, как это реализовать.

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Стек CoreData состоит из трех компонентов: контекста (NSManagedObjectContext), модели (NSManagedObjectModel) и координатора хранилища (NSPersistentStoreCoordinator / NSPersistentStore).

Вам нужно иметь два разных контекста , которые разделяют одну и ту же модель , но используют два разных магазина . Само хранилище будет того же типа (например, база данных SQLite), но будет использовать другой исходный файл.

На этой странице вы можете увидеть документацию по стеку:

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/InitializingtheCoreDataStack.html#//apple_ref/doc/uid/TP40001075-CH4-SW1

NSPersistentContainer - это удобный класс для инициализации стека CoreData.

Возьмите пример инициализации NSPersistentContainer по ссылке: вы можете иметь точно такой же код для его инициализации, дважды , но с той лишь разницей, что два NSPersistentContainer используют различную Файл .sqlite : то есть вы можете иметь два свойства в вашем делегате приложения с именами managedObjectContextForUI и managedObjectContextForSyncing, которые загружают различные файлы .sqlite. Затем в вашей программе вы можете использовать контекст из одного хранилища, чтобы получить текущие данные для показа пользователю, и вы можете использовать контекст, который использует другое хранилище с другим .sqlite, если вы выполняете операции синхронизации. Когда операции синхронизации наконец выполнены, вы можете в конце концов поменять местами два файла и после очистки и перезагрузки NSPersistentContainer (это может быть сложно, потому что вы захотите сделать недействительными и перезагрузить все управляемые объекты: вы переходите в совершенно новый контекст), вы можете затем покажите вновь синхронизированные данные пользователю и снова начните синхронизацию в новом файле .sqlite .

0 голосов
/ 14 января 2019

Как я понимаю, проблема в том, что вы хотите иметь возможность загружать большой «граф объектов». Однако он настолько велик, что его нельзя загрузить сразу в память, поэтому вам придется разбить его на куски, а затем локально объединить с данными Core.

Если это так, я думаю, что это не тривиально. Я не уверен, что могу думать о прямом решении, не понимая объектных отношений, и даже тогда оно может быть действительно подавляющим.

Чрезмерно упрощенным решением может быть создание файла sqlite на сервере и загрузка его порциями; это кажется уродливым, но оно служит для отделения бизнес-логики от синхронизации, то есть файл sqlite становится транспортным уровнем. Итак, я думаю, что суть решения заключается в том, чтобы найти способ физически представлять данные, которые вы синхронизируете, в формате, который позволяет разбивать их на куски и которые впоследствии могут быть объединены в файл sqlite (если вы настаиваете на использовании Core данные).

Обратите также внимание, что, насколько я знаю, Amazon (https://aws.amazon.com/appsync/) и Realm (https://realm.io/blog/introducing-realm-mobile-platform/)) обеспечивают фоновую синхронизацию вашей локальной базы данных, но это платные услуги, и вам следует быть осторожным, чтобы быть заблокирован (не должен зависеть от их библиотек в слое модели, вместо этого иметь слой перевода).

0 голосов
/ 07 января 2019

Ты должен делать именно то, что сказал. Просто создайте класс (давайте назовем его SyncBuffer) с методами «load», «sync» и «save».

Метод load должен читать все сущности из CoreData и сохранять их в переменных класса. Метод sync должен выполнять всю синхронизацию с использованием переменных класса. Наконец, метод «save» должен сохранять все значения из переменных класса в CoreData - здесь вы даже можете удалить все данные из CoreData и сохранить новые значения из SyncBuffer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...