В Задаче C почему мои основные объекты данных никогда не освобождаются? - PullRequest
4 голосов
/ 25 июля 2010

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

Кстати, у меня есть [managedObjectContext setRetainsRegisteredObjects: NO], так что это не проблема.

Вот пример, который я пробовал, который не работает:

MobileObject *obj = [NSEntityDescription insertNewObjectForEntityForName:@"MobileObject" inManagedObjectContext:managedObjectContext];

NSLog(@"Object count after creation %d", [obj retainCount]);

NSError *error;
[managedObjectContext save:&error];

NSLog(@"Object count after saving %d", [obj retainCount]);

В каждом сообщении журнала выводится «2». Dealloc никогда не звонят. Я ожидаю, что сохранение приведет к тому, что объект будет освобожден (или автоматически освобожден), так как данные ядра должны понимать, что не нужно оставаться рядом. В этом случае сохранение количества 2 имеет смысл, если есть два авто-релиза (один из создания и один из сохранения), но это не так. Если я добавлю

[obj release] 

в самом конце моего теста подпрограмма dealloc будет вызвана правильно, но я очень озадачен тем, зачем мне вообще нужен этот выпуск.

Ответы [ 3 ]

6 голосов
/ 25 июля 2010

Сохранение контекста CoreData не логически связано с выпуском NSManagedObject.

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

Итак, если вы хотите освободить сохраняемые объекты, вам необходимо явно освободить их.

Однако в этом случае insertNewObjectForEntityName:inManagedObjectContext: возвращает автоматически освобожденный объект как написано здесь .Таким образом, вы не являетесь владельцем объекта, если не сохраните его явно.Если вы не сохранили, вы не должны выпускать его.Он выпущен, и dealloc вызывается автоматически при необходимости.

Обратите внимание, что вам никогда не следует полагаться на retainCount, чтобы увидеть, что происходит.Для упрощенного объекта число retainCount согласуется с тем, что мы ожидаем, но для чего-то сложного, такого как NSManagedObject, сама структура должна отслеживать множество вещей, и поэтому может делать много retain за кулисами.Например, даже если вы явно не сохраняете объект, он может быть связан с другим объектом, которым вы владеете;или CoreData может просто решить сохранить объект в памяти для его кэширования.

Единственное, что нужно иметь в виду, это придерживаться стандартного правила собственности.Если вы alloc/init или retain, вы позже release или autorelease это.

Отвечая на ваш вопрос в комментарии, позвольте мне изложить здесь основной принцип: если объект x нуждается в другом объекте a, x retain s a.Когда x заканчивается, используя a, x release s a.Каждый объект x должен следовать этой процедуре, независимо от того, является ли x объектом, который вы кодируете, или который предоставляет инфраструктура Apple.Если каждый объект следует этому принципу, утечки нет.Итак, код Apple, который вы не видите, следует за этим.Ваш код также должен следовать этому.

Это отвечает на ваш вопрос:

когда я «добавляю» дочерний объект к родительскому, родительский объект автоматически сохраняет добавленный мной объект?

Да, это так.Родитель нуждается в этом, поэтому он сохраняет его.

И если я затем освобождаю родительский объект, он освободит дочерний элемент или мне придется сделать это явно?

Да, родитель освобождает дочернего элемента, потому что, когда родитель dealloc ed, он заканчивает использование дочернего элемента, поэтому дочерний элемент release ed.

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

Рекомендуем прочитать Правила управления памятью .

2 голосов
/ 26 июля 2010

Core Data будет управлять собственной памятью, вам не нужно об этом беспокоиться.Просто следуйте правилам сохранения / выпуска и позвольте Core Data позаботиться о себе.

Когда вы проверяете утечки, означает, что - это когда вам нужно убедиться, что ваш *Код 1006 * соответствует правилам.

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

Если вы хотите принудительно сбросить память (например, когда вы переходите в фоновый режим на iOS4), вам следует вызвать -reset на вашем NSManagedObjectContext и это заставит Core Data очистить как можно больше памяти.Но даже тогда нет никакой гарантии, что NSManagedObject будет освобожден.Однако это будет ошибкой.

Краткий ответ ... не беспокойтесь об этом.

1 голос
/ 26 июля 2010

Когда вы работаете с управляемыми объектами в Базовых данных, вы обычно не используете retain или release, поскольку Базовые данные заботятся о таких вещах для вас.Если у вас есть объект, который, как вы знаете, вам не нужно использовать какое-то время, вы можете повторно его исправить (это приведет к сокращению его до каркаса, занимающего меньше памяти. Для повторного сбоя NSManagedObject убедитесь, что любые изменения в нембыли сохранены и что любые изменения из других контекстов (если они есть) были объединены, просто позвоните [managedObjectContext refreshObject:objectToFault mergeChanges:NO];

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