ИМХО, какой из вариантов «правильный» - это вопрос предпочтений. Я не возражаю против респондентов, которые выступают за отказ от использования autorelease
, но я предпочитаю использовать autorelease
, если только нет веских причин не делать этого. Я перечислю свои причины, и вы сможете решить, подходят ли они вашему стилю программирования.
Как отметил Чак, существует легенда о том, что использование пулов с автоматическим выпуском связано с некоторыми накладными расходами. Это далеко от истины, и это результат бесчисленных часов, потраченных на Shark.app, чтобы выжать из кода последнюю каплю производительности. Попытка оптимизировать для этого глубоко уклоняется от «преждевременной оптимизации». Если и только если Shark.app предоставит вам достоверные данные, это может быть проблемой, если вы даже подумайте о том, чтобы заглянуть в него.
Как указывали другие, автоматически выпущенный объект «освобождается в какой-то более поздний момент». Это означает, что они задерживаются, занимая память, пока не наступит «более поздний момент». В «большинстве» случаев это находится в конце этапа обработки события, прежде чем цикл выполнения перейдет в режим ожидания до следующего события (таймера, щелчка пользователем чего-либо и т. Д.).
Однако иногда вам нужно будет избавиться от этих временных объектов раньше, чем позже. Например, вам нужно обработать огромный файл размером в несколько мегабайт или десятки тысяч строк из базы данных. Когда это произойдет, вам нужно будет поместить NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
в хорошо выбранную точку, а затем [pool release];
внизу. Это почти всегда происходит при некоторой «пакетной обработке цикла», поэтому обычно это начало и конец какого-то критического цикла. Опять же, это должно быть основано на доказательствах, а не на догадках. ObjectAlloc Instrument.app - это то, что вы используете для поиска этих проблемных мест.
Однако основная причина, по которой я предпочитаю autorelease
release
, заключается в том, что писать программы без утечек намного проще. Короче говоря, если вы решите пойти по маршруту release
, вам необходимо гарантировать, что release
в конечном итоге будет отправлен на obj
при всех обстоятельствах. Хотя это может показаться простым, на самом деле это удивительно сложно сделать на практике. Возьмем, к примеру, ваш пример:
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
// Assume a few more lines of work....
[obj release];
Теперь представьте, что по какой-то причине что-то где-то тонко нарушает ваше предположение, что array
является изменяемым, возможно, в результате использования какого-либо метода для обработки результатов, и возвращенный массив, содержащий обработанные результаты, был создан как NSArray
. Когда вы отправляете addObject:
этому неизменяемому NSArray
, выдается исключение, и вы никогда не отправите obj
его release
сообщение. Или, может быть, что-то пойдет не так где-то между моментом, когда obj
было alloc
d и обязательным вызовом release
, например, вы проверяете какое-то условие, и return()
сразу по ошибке, потому что вам не пришло в голову, что этот вызов release
позже должен иметь место.
Вы только что слили объект. И, вероятно, подписались на несколько дней, чтобы выяснить, где и почему вы его сливаете. По опыту, вы потратите много часов, глядя на этот код выше, убежденные, что он не может быть источником утечки, потому что вы очень четко отправляете obj
a release
. Затем, через несколько дней, вы испытаете то, что можно описать только как религиозное прозрение, когда вы поймете причину проблемы.
Рассмотрим случай autorelease
:
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
// Assume a few more lines of work....
Теперь уже не имеет значения, что произойдет, потому что случайно obj
утечка практически невозможна даже в чрезвычайно необычных или исключительных случаях.
person
johne
schedule
19.07.2009