Используя блоки пула автовыпуска
Блоки пула автовыпуска обеспечивают механизм, посредством чего можно оставить владение объекта, но избегать возможности его освобождаемый сразу (такой как тогда, когда Вы возвращаете объект из метода). Как правило, Вы не должны создавать свои собственные блоки пула автовыпуска, но существуют некоторые ситуации, в которых или Вы должны или это быть выгодными, чтобы сделать так.
О блоках пула автовыпуска
Блок пула автовыпуска отмечен с помощью @autoreleasepool
, как проиллюстрировано в следующем примере:
@autoreleasepool { |
// Code that creates autoreleased objects. |
} |
В конце блока пула автовыпуска, объекты, получившие autorelease
сообщение в блоке отправляется a release
сообщение — объект получает a release
сообщение в течение каждого раза это было отправлено autorelease
сообщение в блоке.
Как любой другой блок кода, могут быть вложены блоки пула автовыпуска:
@autoreleasepool { |
// . . . |
@autoreleasepool { |
// . . . |
} |
. . . |
} |
(Вы обычно не видели бы код точно как выше; обычно код в блоке пула автовыпуска в одном исходном файле вызвал бы код в другом исходном файле, содержащемся в другом блоке пула автовыпуска.) Для данного autorelease
сообщение, соответствие release
сообщение отправляется в конце блока пула автовыпуска в который autorelease
сообщение было отправлено.
Какао всегда ожидает, что код будет выполнен в блоке пула автовыпуска, иначе автовыпустил объекты, не становятся выпущенными и Ваша память утечек приложения. (Если Вы отправляете autorelease
сообщение за пределами блока пула автовыпуска, Какао регистрирует подходящее сообщение об ошибке.) AppKit и платформы UIKit обрабатывают каждую итерацию цикла событий (такую как мышь вниз событие или касание) в блоке пула автовыпуска. Поэтому Вы обычно не должны создавать пул автовыпуска, блокируют себя, или даже видят код, использующийся для создания того. Когда Вы могли бы использовать свои собственные блоки пула автовыпуска, существуют, однако, три случая:
Если Вы пишете программу, которая не является на основе платформы UI, такой как инструмент командной строки.
Если Вы пишете цикл, создающий много временных объектов.
Можно использовать блок пула автовыпуска в цикле для избавления от тех объектов перед следующей итерацией. Используя блок пула автовыпуска в цикле помогает сократить максимальный объем потребляемой памяти приложения.
Если Вы порождаете вторичный поток.
Необходимо создать собственный блок пула автовыпуска, как только поток начинает выполняться; иначе, Ваше приложение пропустит объекты. (См. Блоки Пула Автовыпуска и Потоки для подробных данных.)
Используйте локальные блоки пула автовыпуска для сокращения пикового объема потребляемой памяти
Много программ создают автовыпущенные временные объекты. Эти объекты добавляют к объему потребляемой памяти программы до конца блока. Во многих ситуациях позволяя временным объектам накопиться, пока конец текущей итерации цикла событий не приводит к чрезмерным издержкам; в некоторых ситуациях, однако, можно создать большое количество временных объектов, добавляющих существенно к объему потребляемой памяти и что Вы хотите избавиться более быстро. В этих последних случаях можно создать собственный блок пула автовыпуска. В конце блока выпущены временные объекты, который обычно приводит к их освобождению, таким образом, сокращающему объем потребляемой памяти программы.
Следующий пример показывает, как Вы могли бы использовать локальный блок пула автовыпуска в a for
цикл.
NSArray *urls = <# An array of file URLs #>; |
for (NSURL *url in urls) { |
@autoreleasepool { |
NSError *error; |
NSString *fileContents = [NSString stringWithContentsOfURL:url |
encoding:NSUTF8StringEncoding error:&error]; |
/* Process the string, creating and autoreleasing more objects. */ |
} |
} |
for
цикл обрабатывает один файл за один раз. Любой объект (такой как fileContents
) отправленный autorelease
сообщение в блоке пула автовыпуска выпущено в конце блока.
После блока пула автовыпуска необходимо расценить любой объект, автовыпущенный в блоке, как «избавлено». Не отправляйте сообщение в тот объект или возвращайте его invoker Вашего метода. Если необходимо использовать временный объект вне блока пула автовыпуска, можно сделать так путем отправки a retain
обменивайтесь сообщениями к объекту в блоке и затем отправьте его autorelease
после блока, как проиллюстрировано в этом примере:
– (id)findMatchingObject:(id)anObject { |
id match; |
while (match == nil) { |
@autoreleasepool { |
/* Do a search that creates a lot of temporary objects. */ |
match = [self expensiveSearchForObject:anObject]; |
if (match != nil) { |
[match retain]; /* Keep match around. */ |
} |
} |
} |
return [match autorelease]; /* Let match go and return it. */ |
} |
Отправка retain
к match
в автовыпуске пул блокируют и отправка autorelease
к нему после того, как блок пула автовыпуска расширяет время жизни match
и позволяет ему получать сообщения вне цикла и возвращаться к invoker findMatchingObject:
.
Блоки пула автовыпуска и потоки
Каждый поток в приложении Какао поддерживает свой собственный штабель блоков пула автовыпуска. Если Вы пишете программу Только для основы или если Вы отсоединяете поток, необходимо создать собственный блок пула автовыпуска.
Если Ваше приложение или поток долгосрочны и потенциально генерируют много автовыпущенных объектов, необходимо использовать блоки пула автовыпуска (как AppKit, и UIKit делают на основном потоке); иначе, автовыпущенные объекты накапливаются, и Ваш объем потребляемой памяти растет. Если Ваш отдельный поток не выполняет вызовы Какао, Вы не должны использовать блок пула автовыпуска.