Ответ 1
В коде есть содержится цикл сохранения, но вы можете разбить цикл сохранения в конце рекурсии, установив myBlock
на нуль в случае базы рекурсии (i == 0
).
Лучший способ доказать это - попробовать его, работая под инструментом Allocations, с выключенным "Отменить незаписанные данные при остановке", "Включить учетные записи", отключить "Только отслеживать активные выделения".
Я создал новый проект Xcode с использованием шаблона инструмента командной строки OS X. Здесь вся программа:
#import <Foundation/Foundation.h>
void test() {
__block void (^myBlock)(int) = [^void (int i){
if (i == 0) {
// myBlock = nil;
return;
}
NSLog(@"myBlock=%p %d", myBlock, i);
myBlock(i - 1);
} copy];
myBlock(10);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
test();
}
sleep(1);
return 0;
}
Затем я запустил его под инструментом Allocations с настройками, описанными выше. Затем я изменил "Статистика" на "Консоль" в "Инструменты", чтобы увидеть выход программы:
2012-10-26 12:04:31.391 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 10
2012-10-26 12:04:31.395 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 9
2012-10-26 12:04:31.396 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 8
2012-10-26 12:04:31.397 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 7
2012-10-26 12:04:31.397 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 6
2012-10-26 12:04:31.398 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 5
2012-10-26 12:04:31.398 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 4
2012-10-26 12:04:31.399 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 3
2012-10-26 12:04:31.400 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 2
2012-10-26 12:04:31.401 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 1
<End of Run>
Я скопировал адрес блока (0x7ff142c24700
), изменил "Консоль" на "Список объектов" и вставил адрес в поле поиска. Инструменты показали мне только выделение для блока:
Точка под столбцом Live означает, что блок все еще был выделен при выходе из программы. Он просочился. Я щелкнул стрелку рядом с адресом, чтобы увидеть полную историю выделения блока:
Только одно событие с этим распределением: оно было выделено.
Затем я раскомментировал строку myBlock = nil
в инструкции if (i == 0)
. Затем я снова запустил его под профилировщиком. Система рандомизирует адреса памяти для обеспечения безопасности, поэтому я очистил панель поиска, а затем снова проверил консоль для адреса блока в этом прогоне. На этот раз это было 0x7fc7a1424700
. Я снова переключился на представление "Список объектов" и вставил его в новый адрес 0x7fc7a1424700
. Вот что я увидел:
На этот раз нет столбцов под столбцом Live, что означает, что к моменту выхода программы блок был освобожден. Затем я нажал на стрелку рядом с адресом, чтобы увидеть полную историю:
На этот раз блок был выделен, выпущен и освобожден.