Скажем, у нас есть две сущности в модели Core Data: департаменты и сотрудники.
Отдел имеет отношение "один ко многим" к сотрудникам.
У меня есть следующие ManagedObjectContexts:
- Корень: подключен к координатору постоянных магазинов
- Главная: контекст с родительским корнем
Когда я хочу создать Работника, я делаю следующее:
- У меня есть отдел в главном контексте
- Я создаю Работника в Главном контексте
- Я назначаю Департамент собственности отдела сотрудников
- Я сохраняю главный контекст
- Я сохраняю контекст корня
Это создает цикл сохранения как в основном контексте, так и в корневом контексте.
Если бы я сделал это без дочернего контекста (все в корневом контексте), я мог бы сломать цикл сохранения, вызвав refreshObject:mergeChanges
в Employee. В моей ситуации с двумя контекстами я все еще мог использовать этот метод для разрыва цикла в главном контексте, но как я могу сломать цикл в корневом контексте?
Примечание: это простой пример для описания моей проблемы. В Инструментах я отчетливо вижу, как увеличивается количество распределений. В моем приложении у меня есть контексты, которые идут глубже одного уровня, вызывая еще большую проблему, потому что я получаю новое распределение объектов с циклом сохранения для каждого контекста, который я сохраняю.
Обновление 15/04: NSPrivateQueueConcurrencyType vs NSMainQueueConcurrencyType
После сохранения обоих контекстов я могу выполнить refreshObject:mergeChanges
в главном контексте с помощью объекта "Департамент". Это, как и ожидалось, приведет к повторному отказу объекта "Департамент", нарушит цикл сохранения и освободит объекты отдела и сотрудника в этом контексте.
Следующим шагом будет разрыв цикла сохранения, который существует в корневом контексте (сохранение основного контекста передало сущности в корневой контекст). Я могу сделать тот же трюк здесь и использовать refreshObject:mergeChanges
в корневом контексте с объектом отдела.
Странно: это прекрасно работает, когда мой корневой контекст создается с помощью NSMainQueueConcurrencyType (все распределения перехватываются и освобождаются), но не работает, когда мой корневой контекст создается с помощью NSPrivateQueueConcurrencyType (все распределения перезапускаются, но не освобожден).
Боковое примечание: все операции для корневого контекста выполняются в вызове executeBlock (AndWait)
Обновление 15/04: Часть 2
Когда я делаю другое (бесполезное, потому что нет изменений) сохранение или откат в корневом контексте с помощью NSPrivateQueueConcurrencyType, объекты, как представляется, освобождены. Я не понимаю, почему это не ведет себя так же, как NSMainQueueConcurrencyType.
Обновление 16/04: демонстрационный проект
Я создал демонстрационный проект: http://codegazer.com/code/CoreDataTest.zip
Обновление 21/04: Как добраться
Спасибо, Джоди Хаггинс за вашу помощь!
Я пытаюсь переместить refreshObject:mergeChanges
из моих методов ManagedObject didSave
.
Не могли бы вы объяснить мне разницу между:
[rootContext performBlock:^{
[rootContext save:nil];
for (NSManagedObject *mo in rootContext.registeredObjects)
[rootContext refreshObject:mo mergeChanges:NO];
}];
и
[rootContext performBlock:^{
[rootContext save:nil];
[rootContext performBlock:^{
for (NSManagedObject *mo in rootContext.registeredObjects)
[rootContext refreshObject:mo mergeChanges:NO];
}];
}];
Верхняя часть не освобождает объекты, нижняя делает.