EXC_BAD_ACCESS для mergeChangesFromContextDidSaveNotification
Мы пытаемся отлаживать проблему с несколькими контентами/потоками Core Data, в которой объединение уведомления о сохранении Core Data в наш основной поток NSManagedObjectContext
вызывает спорадическое сбой приложения. Это приводит к сбою ~ 2% от наших сеансов приложений, и мы не понимаем, как это решить. Мы были бы очень признательны за любые рекомендации или общие рекомендации о том, что может привести к этой катастрофе.
У нас есть настройка Core Data, которая выглядит так:
Нотабене Это стандартный стек Core Data в Magical Record v2.3, созданный с помощью [MagicalRecord setupAutoMigratingCoreDataStack]
Это сценарий, в котором наше приложение терпит крах:
- Запрос HTTP возвращает JSON
- JSON анализируется на
NSManagedObject
(некоторые новые сущности, некоторые обновленные объекты) в Контекст сохранения корня
- Контекст сохранения корня сохраняет в постоянном хранилище
-
NSManagedObjectContextDidSaveNotification
транслируется базовыми данными. По умолчанию используется контекст в главной очереди и вызывает mergeChangesFromContextDidSaveNotification:
с NSDictionary
изменений в основном потоке.
- Он вылетает, когда
objectID
отправляется на недопустимый объект (скорее всего, NSManagedObject
был освобожден).
Это происходит внутри частной реализации NSManagedObjectContext
mergeChangesFromContextDidSaveNotification:
, поэтому мы не можем видеть, что на самом деле произошло здесь неправильно; все, что мы можем сказать в этой точке, что объект, который должен существовать, не делает.
![enter image description here]()
Это происходит только при небольшом проценте данных Core Data, что указывает на то, что это не может быть фундаментальным недостатком в нашем стеке Core Data → API. Более того, нет никаких указаний на то, что размер или тип изменений (вставки/обновления/удаления) в контексте изменений оказывают какое-либо влияние на вероятность сбоя.
Ответы
Ответ 1
Прошло некоторое время, так как этот вопрос был опубликован, и после его повторного открытия я хотел бы ответить на свой вопрос ради других, кто нашел эту тему.
В моих обстоятельствах я перенесла большую базу кода из sibling NSManagedObjectContexts
, обновленную через NSManagedObjectContextDidSaveNotification
. Однако проблема не имела в этом никакого отношения, хотя это и вызывало проблему.
Настоящей причиной этого были места, где были старые части кода, которые были установлены предыдущими инженерами, которые установили KVO на NSManagedObject
и их свойства. Выяснилось, что KVO на объектах Core Data на самом деле очень плохая идея.
Точнее, оказалось, что это произошло, когда KVO был настроен на сущности и либо объект, либо цель отношения к этому объекту была удалена из NSPersistentStore
. Это второе условие, казалось, не было единственной причиной проблемы, но определенно было очень заметной причиной в моей ситуации.
Извлеченный урок:
- Используйте выбранный контроллер результатов, когда вам нужно. KVO не является удобным ярлыком, и вам не следует избегать переноса изворотливого кода Core Data KVO на NSFetchedResultsControllers или другой разумной альтернативы, поскольку промедление просто повредит вам.
- Многопоточные базовые данные - это сложный, но очень полезный навык, чтобы стать экспертом. Знание стека Core Data и нюансов и ограничений многопоточности Core Data абсолютно стоит всех душевных страданий.
Ответ 2
В документации NSManagedObjectContextDidSaveNotification
указано, что:
"Вы можете передать объект уведомления в mergeChangesFromContextDidSaveNotification:
в другом потоке, однако вы не должны использовать управляемый объект в словаре пользовательской информации непосредственно в другом потоке. Для получения дополнительной информации см. Concurrency с основными данными в основных данных Руководство по программированию."
Может, это и есть проблема? Я бы удостоверился, что объект u получит из уведомления, который сохраняется в Контексте По умолчанию в том же потоке, который был отправлен Root.
Ответ 3
Одна из возможностей заключается в том, что ваш постоянный магазин поврежден и находится в противоречивом состоянии. Если это произойдет, генерируется код ошибки, с которым Magical Record не обязательно справляется. Это может быть источником ряда трудно-повторяющихся явно-случайных сбоев, связанных с магической записью (и может быть или не может считаться ошибкой Magical Record).
Стоит прочитать "Волшебная запись", которая затрагивает темы здесь (тот же выпуск) и здесь (другая проблема, но может быть аналогичной причиной). Когда я сталкивался с этими проблемами, мне удалось сделать некоторые временные исправления исправлений, следуя различным подсказкам в этих потоках, но в конечном итоге я решил удалить свою зависимость от Magical Record, и с тех пор у меня не было проблем.