Управление изменениями

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

Непересекающиеся редактирования

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

  Контексты Управляемого объекта рисунка 1 со взаимно противоречивыми значениями данных
Managed object contexts with mutually inconsistent data values

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

Обнаружение конфликта и оптимистическая блокировка

Когда Базовые Данные выбирают объект от персистентного хранилища, они берут снимок своего состояния. Снимок является словарем персистентных свойств объекта — обычно все его атрибуты и глобальный IDs любых объектов, к которым он имеет к - одно отношение. Снимки участвуют в оптимистической блокировке. Когда платформа сохраняет, она сравнивает значения в снимке каждого отредактированного объекта с текущими соответствующими значениями в персистентном хранилище.

  • Если значения являются тем же, то хранилище не было изменено, так как объект был выбран, таким образом, сохранение обычно продолжается. Как часть работы сохранения, значения снимков обновляются для соответствия сохраненных данных.

  • Если значения отличаются, то хранилище было изменено, так как объект был выбран или в последний раз сохранен; это представляет оптимистический отказ блокировки.

Разрешение конфликтов

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

Поведение по умолчанию определяется NSErrorMergePolicy. Если существуют какие-либо конфликты слияния, эта политика заставляет сохранение перестать работать. В случае отказа метод сохранения возвращается с ошибкой с a userInfo словарь, содержащий ключ @"conflictList"; соответствующее значение является массивом записей конфликта. Можно использовать массив, чтобы сказать пользователю что различия, там между значениями, которые они пытаются сохранить и текущие в хранилище. Прежде чем можно будет спасти Вас, должен или фиксировать конфликты (путем перевыборки объектов так, чтобы снимки были обновлены), или выберите различную политику. NSErrorMergePolicy единственная политика, генерирующая ошибку. Другие политики —NSMergeByPropertyStoreTrumpMergePolicy, NSMergeByPropertyObjectTrumpMergePolicy, и NSOverwriteMergePolicy— позвольте сохранению продолжаться путем слияния состояния отредактированных объектов с состоянием объектов в хранилище по-разному. NSRollbackMergePolicy отбрасывания изменения состояния в памяти для объектов в конфликте и использовании версия персистентного хранилища состояния объектов.

Управление снимком

Приложение, выбирающее сотни строк данных, может накопить большой кэш снимков. Теоретически, если достаточно выборок выполняется, Базовое Основанное на данных приложение может содержать все содержание хранилища в памяти. Безусловно, снимками нужно управлять для предотвращения этой ситуации.

Ответственность за очистку снимков лежит на вызванном подсчете ссылок снимка механизма. Этот механизм отслеживает управляемые объекты, связанные с определенным снимком — т.е. управляемые объекты, содержащие данные от определенного снимка. Когда нет никаких остающихся экземпляров управляемого объекта, связанных с определенным снимком (который Базовые Данные определяют путем ведения списка этих ссылок), сильная ссылка к снимку повреждается.

Передача изменений между контекстами

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

Рассмотрите заявление с двумя контекстами управляемого объекта и единственным персистентным координатором хранилища. Если пользователь удаляет объект в первом контексте (moc1), Вы, возможно, должны сообщить второму контексту (moc2) это было удалено. Во всех случаях, moc1 сообщения NSManagedObjectContextDidSave уведомление, которое Ваше приложение должно зарегистрировать для и использование в качестве триггера для любых мер, которые это должно принять. Это уведомление содержит информацию не только об удаленных объектах, но также и об измененных объектах. Необходимо обработать эти изменения, так как они могут быть результатом удаления (большинство способов, которыми это может произойти, включают переходные отношения или выбранные свойства).

Существуют многократные оси, которые необходимо рассмотреть при решении, как Вы хотите обработать Ваш удалять уведомление. Важные:

Они являются несколько ортогональными, и какие меры Вы принимаете для синхронизации, контексты зависят от семантики приложения. Следующие три стратегии представлены в порядке увеличивающейся сложности.

  1. Когда сам объект не изменился в, самый простой случай - moc2 и Вы не должны волноваться об отмене; в этой ситуации можно просто удалить объект. В следующий раз moc2 сохраняет, платформа заметит, что Вы пытаетесь повторно удалить объект, проигнорировать оптимистическое предупреждение блокировки и продолжаться без ошибки.

  2. Если Вы не заботитесь о содержании moc2, можно просто сбросить его (использование reset) и повторно выберите любые данные, в которых Вы нуждаетесь после сброса. Это сбросит стек отмены также, и удаленного объекта теперь не стало. Единственная проблема здесь определяет что данные повторно выбрать. Можно сделать это перед сбросом, собирая IDs (objectID) из управляемых объектов Вам все еще нужно и использующий тех для перезагрузки, как только сброс произошел (Вы должны исключить удаленный IDs и лучше создавать запросы выборки с IN предикаты для предотвращения проблем будут, не будучи способен выполнять отказы для удаленного IDs).

  3. Если объект изменился в moc2, но Вы не заботитесь об отмене, Ваша стратегия зависит от того, что это означает для семантики Вашего приложения. Объект если, удаленный в moc1 имеет изменения в moc2, если это удалено из moc2 также? Или это должно быть возрождено, и изменения сохраняются? Что происходит, если исходное удаление инициировало каскадное удаление для объектов, не данных сбой в moc2? Что, если объект был удален как часть каскадного удаления?

    Существует две осуществимых опции (одна треть, неудовлетворительная опция описана позже):

    1. Самая простая стратегия состоит в том, чтобы просто отбросить изменения путем удаления объекта.

    2. Также, если объект автономен, можно установить политику слияния по контексту к NSMergePolicyOverwrite. Это заставит изменения во втором контексте перезаписывать удаление в базе данных.

      Обратите внимание на то, что это вызовет все изменения в moc2 перезаписывать любые изменения, внесенные в moc1.

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

  1. Если у Вас есть ситуация как 3 (b) выше, но объект, не автономный, и по некоторым причинам, Вы хотите сохранить те изменения, лучшее, которое Вы, вероятно, будете в состоянии сделать, должно возродить часть графика, загруженного в moc2, который может или может не быть целесообразным в контексте Вашего приложения. Снова Вы делаете это путем установки политики слияния в NSMergePolicyOverwrite, но Вам также нужны некоторое первичное проектирование приложений и некоторые влезающие в объекты в отношениях 'удаленного' объекта.

    Для мира для создания некоторой суммы смысла позже необходимо автоматически дать сбой в любых отношениях, которые, возможно, должны были бы быть возрождены, когда Вы даете сбой в объекте. Затем когда Вы получаете удалить уведомление, необходимо заставить контекст думать, что все объекты, связанные с удаленным объектом, изменились, так, чтобы они были сохранены также. Это чрезмерно увеличит размер использования памяти Вашего приложения, так как Вы закончите с возможно несоответствующими данными предусмотрительно против чего-то, что может не произойти, и если Вы не осторожны, можно закончить с базой данных в гибридном состоянии, где это ни один что moc1 попробованный для создания, ни что moc2 ожидал бы (например, если бы Вы пропустили отношение где-нибудь, и у Вас теперь есть частичные отношения или осиротевшие узлы).

  2. Второй с конца из всех миров - когда у Вас есть изменения в других объектах, Вы не можете сдуть во втором MOC, сам объект имеет изменения, которые Вы готовы отбросить, и Вы заботитесь об отмене. Вы не можете сбросить контекст, потому что это теряет изменения. При удалении объекта удаление будет продвинуто на стек отмены и будет невыполнимым, таким образом, пользователь мог отменить, повторно сохранить и столкнуться с семантическими проблемами, упомянутыми в 3 выше, только хуже, потому что Вы не запланировали их.

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

  3. Худший случай - Вы, имеют изменения в других объектах, которые Вы не можете отбросить, объект имеет изменения, которые Вы хотите сохранить, и Вы заботитесь об отмене. Может быть способ иметь дело с этим, но он потребует значительного усилия, и любое решение, вероятно, будет сложным и хрупким.