Поиск и устранение неисправностей базовых данных

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

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

Объектные проблемы жизненного цикла

Ошибки слияния

Проблема: Вы видите сообщение об ошибке, "Could not merge changes".

Причина: Два различных контекста управляемого объекта попытались изменить те же данные. Это также известно как оптимистический отказ блокировки.

Средство: Или установите политику слияния по контексту, или вручную (программно) разрешите отказ. Можно получить в настоящее время зафиксированные значения для объектного использования committedValuesForKeys:, и можно повторно дать сбой объект (так, чтобы, когда к нему затем получают доступ, его значения данных были получены от его персистентного хранилища), использование refreshObject:mergeChanges:.

Присвоение управляемого объекта к различному хранилищу

Проблема: Вы видите исключение, выглядящее подобным этому примеру.

<NSInvalidArgumentException> [<MyMO 0x3036b0>_assignObject:toPersistentStore:]:
Can’t reassign an object to a different store once it has been saved.

Причина: объект, который Вы пытаетесь присвоить хранилищу, был уже присвоен и сохранен к различному хранилищу.

Средство: Для перемещения объекта от одного хранилища до другого необходимо создать новый экземпляр, скопировать информацию со старого объекта, сохранить его к надлежащему хранилищу, и затем удалить старый экземпляр.

Отказ не может быть выполнен

Проблема: Вы видите сообщение об ошибке, "Core Data could not fulfill a fault".

Причина: базовые данные соответствующего объекта были удалены из персистентного хранилища.

Средство: необходимо отбросить этот объект.

Эта проблема может произойти по крайней мере в двух ситуациях:

Во-первых:

  • Запустите с сильной ссылки к управляемому объекту.

  • Удалите управляемый объект через контекст управляемого объекта.

  • Сохраните изменения на контексте объекта.

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

  • Попытайтесь получить атрибут или отношение из ранее сохраненной ссылки.

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

Во-вторых:

  • Удалите объект из контекста управляемого объекта.

  • Не удается повредить все отношения от других объектов до того объекта.

  • Сохраните изменения.

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

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

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

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

Управляемый объект лишен законной силы

Проблема: Вы видите исключение, выглядящее подобным этому примеру:

<NSObjectInaccessibleException> [<MyMO 0x3036b0>_assignObject:toPersistentStore:]:
The NSManagedObject with ID:#### has been invalidated.

Причина: Или Вы удалили хранилище для отказа, который Вы пытаетесь запустить, или контекст управляемого объекта был отправлен a reset сообщение.

Средство: необходимо отбросить этот объект. Если Вы добавляете хранилище снова, можно попытаться выбрать объект снова.

Класс не является значением ключа, кодирующим совместимый

Проблема: Вы видите исключение, выглядящее подобным следующему примеру.

<NSUnknownKeyException> [<MyMO 0x3036b0> valueForUndefinedKey:]:
this class is not key value coding-compliant for the key randomKey.

Причина: Или Вы использовали неправильный ключ, или Вы инициализировали свой управляемый объект с init вместо initWithEntity:inManagedObjectContext:.

Средство: Используйте допустимый ключ (проверьте, что написание и случай тщательно — также рассматривают правила для соответствия кодирования значения ключа в Значении ключа, Кодирующем Руководство по программированию), или гарантируйте, чтобы Вы использовали определяемый инициализатор для NSManagedObject (см. initWithEntity:insertIntoManagedObjectContext:).

Класс объекта не реагирует на вызовы пользовательских методов

Проблема: Вы определяете объект, использующий пользовательский подкласс NSManagedObject, тогда в коде Вы создаете экземпляр объекта и вызываете пользовательский метод, как проиллюстрировано в этом фрагменте кода:

NSManagedObject *entityInstance =
    [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity"
            inManagedObjectContext:managedObjectContext];
[entityInstance setAttribute: newValue];

Вы получаете ошибку периода выполнения как это:

"2005-05-05 15:44:51.233 MyApp[1234] ***
    -[NSManagedObject setNameOfEntity:]: selector not recognized [self = 0x30e340]

Причина: В модели Вы, возможно, написали имя c орфографическими ошибками пользовательского класса для объекта.

Средство: Гарантируйте, что написание имени пользовательского класса в модели соответствует написание пользовательского класса, который Вы реализуете.

Пользовательские методы доступа не вызываются, ключевым зависимостям не повинуются

Проблема: Вы определяете пользовательский подкласс NSManagedObject для определенного объекта и реализуют пользовательские методы средств доступа (и возможно зависимые ключи). Во время выполнения не вызывают методы доступа, и зависимый ключ не обновляется.

Причина: В модели Вы не указывали пользовательский класс для объекта.

Средство: Гарантируйте, что модель указывает имени пользовательского класса для объекта (т.е. что это не NSManagedObject).

Проблемы с выборкой

Хранилище SQLite не работает с сортировкой

Проблема: Вы создаете дескриптор вида, использующий метод сравнения, определенный NSString, такой как следующее:

NSSortDescriptor *mySortDescriptor = [[NSSortDescriptor alloc]
        initWithKey:@"lastName" ascending:YES
        selector:@selector(localizedCaseInsensitiveCompare:)];

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

NSRunLoop ignoring exception 'unsupported NSSortDescriptor selector:
        localizedCaseInsensitiveCompare:' that raised during posting of
        delayed perform with target 3e2e42 and selector 'invokeWithTarget:'

Причина: Точно то, как запрос выборки выполняется, зависит от хранилища — посмотрите Выбирающие Управляемые объекты.

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

Проблемы с сохранением

Хранилище SQLite занимает много времени для сохранения

Проблема: Вы используете хранилище SQLite и замечаете, что занимает больше времени сохранить к хранилищу SQLite, чем это делает для сохранения тех же данных к хранилищу XML.

Причина: Это - вероятно, ожидаемое поведение. Хранилище SQLite гарантирует, что все данные записаны правильно в диск — посмотрите Конфигурирование Поведения Сохранения Хранилища SQLite.

Средство: Сначала определите, будет ли время, потраченное для сохранения, примечательно пользователю. Это, обычно вероятно, будет иметь место, только если Вы конфигурируете свое приложение для частого сохранения автоматически — например, после каждого редактирования, которое делает пользователь. Во-первых, рассмотрите изменение поведения сохранения хранилища (выключите полную синхронизацию). Тогда рассмотрите сохраняющие данные только после периода набора (например, каждые 15 секунд) вместо после каждого редактирования. Если необходимо, рассмотрите выбор различного хранилища — например, двоичного хранилища.

Не может сохранить документы, потому что объект является нулем

Проблема: у Вас есть Базовые Данные основанное на документе приложение, которое неспособно сохранить. Когда Вы пытаетесь сохранить документ, Вы получаете исключение:

Exception raised during posting of notification.  Ignored.  exception: Cannot perform operation since entity with name 'Wxyz' cannot be found

Причина: Эта ошибка испускается экземпляром NSObjectController (или один из его подклассов), который установлен в режиме Entity, но не может получить доступ к описанию объекта в модели управляемого объекта, связанной с именем объекта, указанным в Интерфейсном Разработчике. Короче говоря, у Вас есть контроллер в режиме объекта с недопустимым именем объекта.

Средство: Выберите поочередно каждый из своих контроллеров в Интерфейсном Разработчике и нажмите Command 1, чтобы показать инспектору. Для каждого контроллера гарантируйте, чтобы у Вас было допустимое имя объекта в поле «Entity Name» наверху.

Исключение сгенерировано в retainedDataForObjectID:withContext.

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

[date] My App[2529:4b03] cannot find data for a temporary oid: 0x60797a0 <<x-coredata:///MyClass/t8BB18D3A-0495-4BBE-840F-AF0D92E549FA195>x-coredata:///MyClass/t8BB18D3A-0495-4BBE-840F-AF0D92E549FA195>

исключение в -[NSSQLCore retainedDataForObjectID:withContext:], и след похож:

#1    0x9599a6ac in -[NSSQLCore retainedDataForObjectID:withContext:]
#2    0x95990238 in -[NSPersistentStoreCoordinator(_NSInternalMethods) _conflictsWithRowCacheForObject:andStore:]
#3    0x95990548 in -[NSPersistentStoreCoordinator(_NSInternalMethods) _checkRequestForStore:originalRequest:andOptimisticLocking:]
#4    0x9594e8f0 in -[NSPersistentStoreCoordinator(_NSInternalMethods) executeRequest:withContext:]
#5    0x959617ec in -[NSManagedObjectContext save:]

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

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

Причина: Вы, возможно, вынудили недавно вставленный объект «потерять» свое вставленное состояние и затем изменили или удалили его. Это могло произойти при передаче временного объекта ID objectWithID:. Вы, возможно, передали вставленный объект другому контексту управляемого объекта.

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

  • Не передавайте вставленный (еще не сохраненный) объект к другому контексту. Только сохраненные объекты могут быть переданы между контекстами.

  • Не вызывать refreshObject: на недавно-вставленном-объекте.

  • Не делайте отношение к объекту, который Вы никогда не вставляете в контекст.

  • Гарантируйте, чтобы Вы использовали определяемый инициализатор для экземпляров NSManagedObject.

Перед сохранением (кадр № 6 в отслеживании стека), контекст updatedObjects и deletedObjects наборы должны только иметь элементы, идентификатор объекта которых возвращается NO от isTemporaryID.

Отладка выборки

С версией 10.4.3 OS X и позже, можно использовать пользовательское значение по умолчанию com.apple.CoreData.SQLDebug зарегистрировать к stderr фактический SQL отправил к SQLite. (Обратите внимание на то, что пользовательские имена по умолчанию чувствительны к регистру.), Например, можно передать следующий как параметр приложению:

-com.apple.CoreData.SQLDebug 1

Более высокие уровни чисел отладки производят больше информации, несмотря на то, что использование более высоких чисел, вероятно, будет иметь уменьшение утилиты.

Информация, которую предоставляет вывод, может быть полезной при отладке проблем производительности — в частности это может сказать Вам, когда Базовые Данные выполняют большое количество маленьких выборок (такой, запуская отказы индивидуально). Как файловый ввод-вывод, выполнение многих маленьких выборок является дорогим по сравнению с выполнением единственной большой выборки. Для примеров того, как исправить эту ситуацию, посмотрите Дающее сбой Поведение.

Модели управляемого объекта

Мое приложение генерирует сообщение «+entityForName: не мог определить местоположение NSManagedObjectModel»

Проблема: ошибка четко дает понять проблему — описание объекта не может найти модель управляемого объекта, от которой можно получить доступ к информации об объекте.

Причина: модель не может быть включена в Ваши ресурсы приложений. Можно пытаться получить доступ к модели, прежде чем она была загружена. Ссылка на контекст может быть nil.

Средство: убедитесь, что модель включена в Ваши ресурсы приложений и что выбрана соответствующая «целевая» опция проекта в XCode.

Метод класса, который Вы вызвали, требует имени объекта и контекста, и именно через контекст объект получает модель. В основном это похоже:

контекст---> координатор---> модель

В целом при работе с Базовыми Данными и у Вас есть проблемы как они, необходимо гарантировать:

  • То, что контекст управляемого объекта не nil

    При установке ссылки на контекст в файле пера удостоверьтесь, надлежащий выход или привязка установлены правильно.

  • При управлении собственным Базовым Стеком данных что контекст управляемого объекта имеет связанного координатора (setPersistentStoreCoordinator: после выделения)

  • То, что у персистентного координатора хранилища есть допустимая модель

Если Вы используете NSPersistentDocument, тогда модель управляемого объекта инстанцируют с помощью mergedModelFromBundles: метод, когда инициализируется документ.

Документация также дает Вам достаточно информации о том, как отладить и рычаги для отладки: существует ряд методов, перечисленных в разделе «Getting and setting the persistence objects» ссылки API для NSPersistentDocument или для изменения или для проверки Базовых Объектов данных Ваш документ работает с. Просто переопределение реализаций, вызов супер и проверка возвращенных значений дали бы Вам больше информации о том, что может (или не может) происходить.

Интеграция привязки

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

Пользовательские мутаторные методы набора отношения не вызываются контроллером массива

Проблема: Вы реализовали мутаторные методы набора для отношения, как описано в Пользовательском К - Много Методов доступа Отношения и связали contentSet привязка NSArrayController когда Вы добавляете объекты к и удаляете объекты из контроллера массива, экземпляр к отношению, но мутаторные методы набора не вызывается.

Причина: Это - ошибка.

Средство: можно работать вокруг этого путем добавления self к contentSet ключевой путь привязки. Например, вместо того, чтобы связать с [Контроллер Объекта Отдела].selection.employees, Вы связали бы с [Контроллер Объекта Отдела].selection.self.employees.

Не может получить доступ к содержанию объектного контроллера после того, как будет загружено перо

Проблема: Вы хотите выполнить работу с содержанием объектного контроллера (экземпляр NSObjectController, NSArrayController, или NSTreeController) после того, как файл пера был загружен, но содержание контроллера nil.

Причина: выборка контроллера выполняется как задержанная работа, выполняемая после того, как ее контекст управляемого объекта установлен (загрузкой пера) — выборка поэтому происходит после awakeFromNib и windowControllerDidLoadNib:.

Средство: можно выполнить выборку «вручную» с fetchWithRequest:merge:error:— посмотрите базовую привязку данных и какао.

Не может создать новые объекты с контроллером массива

Проблема: Вы не можете создать новые объекты с помощью NSArrayController. Например, когда Вы нажимаете кнопку, присвоенную add: действие, Вы получаете ошибку, подобную следующему:

2005-05-05 12:00:)).000 MyApp[1234] *** NSRunLoop
ignoring exception 'Failed to create new object' that raised
during posting of delayed perform with target 123456
and selector 'invokeWithTarget:'

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

Средство: Реализуйте пользовательский класс или укажите, что объект представлен NSManagedObject.

Табличное представление, связанное с контроллером массива, не выводит на экран содержание отношения

Проблема: Вам связали табличное представление с контроллером массива, что Вы хотите вывести на экран содержание отношения, но ничто не выведено на экран, и Вы получаете ошибку, подобную следующему:

2005-05-27 14:13:39.077 MyApp[1234] *** NSRunLoop ignoring exception
'Cannot create NSArray from object <_NSFaultingMutableSet: 0x3818f0> ()
of class _NSFaultingMutableSet - consider using contentSet
binding instead of contentArray binding' that raised during posting of
delayed perform with target 385350 and selector 'invokeWithTarget:'

Причина: Вы связали контроллер contentArray привязка с отношением. Отношения представлены наборами.

Средство: Свяжите контроллер contentSet привязка с отношением.

Новый объект не добавляется к отношению объекта, в настоящее время выбираемого в табличном представлении

Проблема: у Вас есть табличное представление, выводящее на экран набор экземпляров объекта. Объект имеет отношение к другому объекту, экземпляры которого выведены на экран во втором табличном представлении. Каждым табличным представлением управляет контроллер массива. Когда Вы добавляете новые экземпляры второго объекта, они не добавляются к отношению выбранного в настоящее время экземпляра первого.

Причина: Эти два контроллера массива не связаны. Нет ничего для сообщения второго контроллера массива о первом.

Средство: Свяжите второй контроллер массива contentSet привязка с ключевым путем, указывающим отношение выбора в первом контроллере массива. Например, если первый контроллер массива управляет объектом Отдела и вторым объект Сотрудника, то contentSet привязка второго контроллера массива должна быть [Department Controller].selection.employees.

Табличное представление или содержание представления схемы не были в курсе, когда связано с объектом NSArrayController или NSTreeController

Проблема: Вы имеете табличное представление или обрисовываете в общих чертах представление, выводящее на экран набор экземпляров объекта. Поскольку новые экземпляры объекта добавлены и удалены, табличное представление не сохранено в синхронизации.

Причина: Если содержание контроллера является массивом, которым Вы управляете сами, то возможно, что Вы не изменяете массив в пути, который является значением ключа, наблюдающим совместимый.

Если содержание контроллера выбирается автоматически, то Вы, вероятно, не установили контроллер в, «Автоматически подготавливают содержание».

Также контроллер не может быть должным образом сконфигурирован.

Средство: Если содержание контроллера является набором, которым Вы управляете сами, то гарантируете, чтобы Вы изменили набор в пути, который является значением ключа, наблюдающим совместимый — посмотрите Привязку Какао Поиска и устранения неисправностей.

Если содержание контроллера выбирается автоматически, установите переключатель «Automatically prepares content» для контроллера в инспекторе Атрибутов в Интерфейсном Разработчике (см. также automaticallyPreparesContent). Выполнение так означает, что дорожки контроллера вставляют в и удаления от его контекста управляемого объекта для его объекта.

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