Если литерал блока сохраняет указанные блоки, выделенные в куче

Рассмотрим следующий код:

// t included so block1 is a stack block. See [1] below
int t = 1;
SimpleBlock block1 = ^{ NSLog(@"block1, %d", t); };

// copy block1 to the heap
SimpleBlock block1_copied = [block1 copy];

// block2 is allocated on the stack, and refers to
// block1 on the stack and block1_copied on the heap
SimpleBlock block2 = ^{
    NSLog(@"block2");
    block1_copied();
    block1();
};
[block1_copied release];

// When the next line of code is executed, block2_copied is
// allocated at the same memory address on on the heap as
// block1_copied, indicating that block1_copied has been
// deallocated. Why didn't block2 retain block1_copied?

SimpleBlock block2_copied = [block2 copy];
block2_copied();
[block2_copied release];

Где, для полноты, SimpleBlock определяется следующим образом:

typedef void (^SimpleBlock)(void);

Как указано в комментарии в коде, my тесты (с использованием как GCC 4.2, так и LLVM 2.0) показывают, что block1_copied освобождается к моменту вызова [block2 copy], однако согласно документации, которую я прочитал [1,3], блоки являются объектами objective-c, а блоки сохраняют цель -c объекты, на которые они ссылаются [2] (в случае переменных, не являющихся экземплярами).

Кроме того, обратите внимание, что при копировании block2 его ссылка на block1 также изменяется на ссылку на новую копию block1 (которая отличается от block1_copied), как и ожидалось, поскольку блоки копируют любые блоки, на которые они ссылаются [2 ].

Итак, что здесь происходит?

A) Если блоки сохраняют объекты objective-c, на которые они ссылаются, а блоки являются объектами objective-c, почему block1_copied освобождается до того, как block2 выходит из области видимости?

B) Если блоки копируют блоки, на которые они ссылаются, и если отправка - (id) copy в блок, выделенный кучей, фактически просто увеличивает его счетчик сохранения, почему block1_copied освобождается до того, как блок2 выходит за пределы области видимости?

C) Если это ожидаемое поведение, где документация, объясняющая это?

[1] http://cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html
[2] http://developer.apple.com/ библиотека / ios / # документация / какао / концептуальные / блоки / статьи / bxVariables.html
[3] http://clang.llvm.org/docs/BlockLanguageSpec.txt

Сноска: в моих тестах результатом выполнения этого кода является бесконечно рекурсивный вызов block2_copied (), поскольку block1_copied () имел тот же адрес памяти, что и у block2_copied.

16
задан Andrew Hershberger 14 September 2011 в 14:59
поделиться