Спасибо всем за ответы. Эти ответы помогли, хотя только в нескольких местах, остальное я должен был выяснить сам. Я был гораздо больше сосредоточен на идее, а не на построчной реализации, но это было трудно описать здесь без вставки огромных кусков кода. Просто делегат для разбора объекта xml является очень конкретным примером, потому что он не возвращает значение само по себе, значение должно быть взято и назначено извне.
Я отмечаю ответ Адама как лучший, как наиболее подробный, хотя и не отвечаю на все мои проблемы.
Для других - http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html - отличное чтение. Также читайте мои собственные ответы на вопросы:
1 - Конечно, я не должен выпускать этот объект. Утечка памяти не была вызвана этим.
2 - Этот метод не является чем-то особенным, он просто возвращает простой автоматически выпущенный объект, как другие пытались объяснить мне здесь. Корень моих начальных проблем заключался в том, что у меня раньше не было этого сохранения, но вскоре я вызвал [release release], что вызвало пул авто-релиза, отправляющий выпуск несуществующему объекту. Я не должен делать [выпуск модели], потому что я не владелец этого объекта. На самом деле, это сохранение здесь даже не нужно, потому что мне просто нужен объект, чтобы получить значение из него, а затем я могу перебрать его, чтобы его можно было безопасно передать в пул авто-релиза без сохранения.
3 - Я хотел, чтобы этот метод (loadData) был независимым, поэтому не устанавливал переменные экземпляра, а возвращал массив для других. Это был параллельный пример, не то чтобы у меня в методе были две переменные с одинаковым именем.
Если я объявляю объект в этом методе (ситуация # 2), то просто так получается, что он автоматически освобождается в конце этого метода, потому что после его завершения элемент управления возвращается к приложению и освобождает пул. хорошо со мной в этом примере, потому что мне не нужен массив позже. В реальном мире у меня, вероятно, должна быть переменная экземпляра (ситуация # 1), а затем идти с self.objectArray = [self loadData], потому что это запустит установщик, и объект с автоматически выпущенным объектом будет сохранен для меня здесь.
4 - Я кое-что перепутал здесь. По сути, я пытался написать код objecive-c с ручным управлением памятью, но все еще придерживался позиции «сборщика мусора». Очень важно помнить, что если вы выполняете [[alloc alloc] init], а затем [освобождение объекта] - это не обязательно означает, что объект будет уничтожен! Релиз не отменяет! Это, конечно, фундаментальное правило (сохранить / освободить), но даже зная его, его легко забыть. Следите за тем, что вы делаете со своим объектом, между этими двумя линиями - объект может действительно прожить очень долго, потому что «кто-то» станет его владельцем. Метод release в конце этого класса livecycle не означает - объект теперь уничтожен, но означает: «Мне уже все равно, мои руки чисты» *
Итак, строка за строкой:
objectArray = [[parserDelegate objectArray] copy];
Это прекрасно, я не копирую глубоко. Я копирую массив, что означает, что он выделяет новую память для объекта массива, но не для содержимого. НО, копия, отправленная в objectArray, также отправляет сохранение каждому объекту. В моем примере я выпускаю свой parserDelegate, который также выпускает свой собственный objectArray, уменьшая retainCount для каждого объекта. Если я не сделаю копию здесь, объекты достигнут retainCount = 0 и будут уничтожены. Таким образом, у меня есть новый массив с указателями на старые объекты, но они по сути становятся моими объектами, потому что предыдущий массив уничтожен, и из-за моего сохранения я становлюсь владельцем. Извините, если это говорит слишком много, но я действительно должен был сосредоточиться, чтобы понять это.
else if ([elementName isEqualToString:@"name"]) {
// do i have to init currentObject.name (NSString) here? i guess not?
[self setParseChars:YES]; // just set the flag to make parse control easier
}
Вопрос здесь заключался в том, следует ли мне инициализировать свойство currentObject.name NSString, потому что оно будет заполнено вскоре после запуска foundCharacters. Теперь это интересно. Когда вы инициализируете весь объект, его свойства NSString равны нулю. Теперь, позже, я делаю
currentObject.name = currentChars;
Который запускает сеттер. Этот установщик определен как (неатомный, сохраняемый), что означает, что новое значение сохраняется, старое значение освобождается и указатель назначается. Как ни странно, не имеет значения, инициализировано ли предыдущее значение или оно равно нулю - если оно инициализировано, оно все равно будет выпущено, если оно равно нулю, то ноль все еще может принять выпуск (хотя я не уверен на 100% ?) - ничего не случится. Но для корректности, я думаю, начальная строка должна выглядеть так:
else if ([elementName isEqualToString:@"name"]) {
currentObject.name = [NSString new]; // just alloc/init routine
[self setParseChars:YES]; // just set the flag to make parse control easier
}
Сейчас:
[currentChars autorelease];
Не должно быть там. Это сбивает с толку дизайн, и это было плохое решение. Все, что должно быть там, это просто строка init.
[objectArray addObject:[currentObject copy]];
Копирование здесь не требуется. addObject сохранит в любом случае. Нет смысла создавать другое распределение. Это было моей одной из причин моих утечек.
Все остальное в порядке. Поскольку я освобождаю currentChars сразу после установки значения для моего объекта, он теперь сохраняет его и становится владельцем, а я просто освобождаю его «здесь» в синтаксическом анализаторе, потому что он мне больше не нужен (это будет выделено в следующем цикле).
Это может сбивать с толку, но я могу себе представить, что будут другие с нестандартными проблемами с назначением памяти, и даже для опытных людей может быть проблемой расставить вещи по местам. Может быть, тогда моя история поможет.