Отладка NSObjectInaccessibleException — объект NSManagedObject с идентификатором: 0x123456789 признан недействительным

У меня есть ошибка, которую я изо всех сил пытаюсь отследить. Я считаю, что происходит то, что я удаляю объект из базовой базы данных, в то время как другой контекст управляемого объекта (в другом потоке) имеет ошибку и получает «NSObjectInaccessibleException», когда он пытается выполнить ошибку.

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

Отсюда мой вопрос: есть ли какие-то приемы, которые я упускаю при отладке CoreData - могу ли я отслеживать время жизни объектов из одного контекста в другом? т.е. когда я удаляю свой объект, есть ли простой способ узнать, есть ли в других контекстах ссылка на этот же объект? Используя это, я мог бы создать тестовый код, чтобы проверить мою логику и найти ошибку.


person Rog    schedule 09.08.2009    source источник
comment
Джим, почему ты выбросил бирку с моим айфоном? Я работаю на iPhone, поэтому у меня нет привязок CoreData.   -  person Rog    schedule 11.08.2009
comment
Роджер, я вернул бирку с айфона. Но на самом деле это общая проблема с основными данными, которая может возникнуть как на настольной, так и на мобильной платформе.   -  person Jim Correia    schedule 11.08.2009
comment
Итак, я диагностировал это, и это проблема iPhone, хотя это может произойти где угодно.   -  person Rog    schedule 31.10.2009
comment
Бен, зачем удалять тег, специфичный для iPhone, и добавлять какао-тач (тег, специфичный для iPhone)?   -  person Rog    schedule 04.08.2015


Ответы (4)


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

В моем случае контекст был "пустым" контекстом, который исчезает при закрытии представления. Однако у меня было фоновое задание, созданное представлением, которое хотело обновить объект.

Я закончил тем, что сделал метод доступа для управляемого объекта, который возвращал nil, когда [managedObject isFault] был истинным. Затем в своем коде я проверял значение этого селектора доступа, чтобы убедиться, что у меня есть допустимый объект для работы (скажем, когда мое фоновое задание наконец завершило свою работу).

Я новичок в Core Data, поэтому, вероятно, есть лучший/умный способ сделать это, но я думаю, что это решило проблему для меня.

person Jason    schedule 28.10.2009
comment
Джейсон, спасибо, что обратил мое внимание на это. Недавно я исправил свою ошибку, это была комбинация очистки и MapKit - представления карты слишком долго сохраняют свой делегат. В вашем случае вам, вероятно, не следует обращаться к тому же контексту NSMAnagedObject из вашего фонового потока - CoreData не является потокобезопасным. Вместо этого вы должны передать NSManagedObjectReference своей фоновой задаче. - person Rog; 31.10.2009
comment
Да, ты определенно прав. В моем случае я возвращался к основному потоку (где я создаю все контексты) до фактического редактирования объекта, но это все равно нехорошо, когда его контекст ушел до свидания. - person Jason; 02.11.2009
comment
Что это за NSManagedObjectReference, о котором вы говорите? По документам не существует... - person Adam; 10.07.2010
comment
Вероятно, он имел в виду NSManagedObjectIDs. - person raheel; 03.07.2012

Я тоже только что столкнулся с этой проблемой. Я провел некоторый рефакторинг, чтобы следовать шаблону Apple «найди или создай» для массового импорта данных. Я создал новый контекст, предназначенный для импорта, установив undomanager на ноль, как было предложено. Так:

// create a new special context for the bulk import of data
NSManagedObjectContext *importContext = [[NSManagedObjectContext alloc] init];
[importContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

// avoid tracking for undo/redo operations
[importContext setUndoManager:nil];

затем я создал fetchRequest для получения идентификаторов объектов, хранящихся в базе данных, и внутри цикла импорта я проверил идентификатор объекта, чтобы определить, содержится ли он в массиве полученных идентификаторов... проблема заключалась в том, что в заданный интервал времени я сохранял importContext и его сброс. И поскольку я ошибочно ссылался на importContext, а не на defaultContext, я получаю эту ошибку. Я исправил, просто изменив:

NSArray *storedObjects = [importContext executeFetchRequest:checkRequest error:&fetchError];

с участием:

NSArray *storedObjects = [defaultContext executeFetchRequest:checkRequest error:&fetchError];
person daveoncode    schedule 06.07.2011
comment
Небольшое примечание для пользователей iOS. В iOS свойство undoManager по умолчанию равно nil. - person stigi; 25.09.2013

Что делает второй контекст, когда он пытается ошибиться в объекте, который был удален из постоянного хранилища?

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

Обычно вы хотите объединить изменения из однорангового контекста, используя -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:].

person Jim Correia    schedule 11.08.2009
comment
Я думаю, что здесь есть две ошибки, и я согласен с тем, что они есть :-( Мне нужен способ их отследить. - person Rog; 11.08.2009
comment
Вы объединяете изменения из ваших одноранговых контекстов? В целях отладки вы можете регистрировать удаленные объекты при каждом сохранении контекста. Если вы знаете, что такое все другие существующие контексты, вы также можете проверить объекты, зарегистрированные в этих контекстах, но вам придется делать это безопасным для потоков способом. - person Jim Correia; 11.08.2009
comment
Ты прав. Я решил, что мне нужно исправить всю ситуацию с потоками, чтобы устранить этот дефект. Это не тривиально, но, вероятно, полезно для моего здоровья. - person Rog; 12.08.2009

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

Исправление было таким, как описано в сообщении блога Джейка — установите для делегата значение nil, когда закончите с представлением карты.

person Rog    schedule 31.10.2009
comment
ссылка не работает. у вас есть новый, или вы могли бы объяснить? - person bearMountain; 03.10.2012
comment
Я думал, что сделал. Проблема в том, что некоторые классы содержат слабую ссылку на своего делегата и отправляют ему сообщения после того, как он был освобожден. Если вы столкнулись с этой проблемой, убедитесь, что вы обнулили ссылки делегирования (или источника данных) в любом классе, делегатом которого вы являетесь. - person Rog; 03.10.2012
comment
Спасибо за разъяснения. - person bearMountain; 15.10.2012
comment
Это было проблемой и для меня на iOS 8.0. В делегате я обращался к управляемому объекту, который я удалил. - person blkhp19; 01.04.2015