Я не знаю, какие шаблоны блока я должен избегать для литеральной области в objective-c
В яблочных документах сказано: Блок-литерал (т.е. ^ {...}) является адресом локальной структуры данных стека, которая представляет блок. Таким образом, объем локальной структуры данных стека является составной составной формулой, поэтому вам следует избегать шаблонов, показанных в следующих примерах:
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop.
}
//for example I invoke the block here
blockArray[1]();
}
void dontDoThisEither() {
void (^block)(void);
int i = random():
if (i > 1000) {
block = ^{ printf("got i at: %d\n", i); };
// WRONG: The block literal scope is the "then" clause.
}
// ...
}
Я не знаю, какие шаблоны я должен избегать.
Похоже, что я мог бы вызывать блок, у которого есть такая же область литералов, что и определение блока, например, за выражением "if" или "for".
Не могли бы вы помочь мне объяснить это?
Вот ссылка https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1
Ответы
Ответ 1
Я думаю, что аналогия с указателями такова:
void foo() {
int *block = NULL;
{
int a;
block = &a;
}
// `block`, even though defined here, points to
// an invalid memory address.
}
Как правило, блок-литерал сам существует только в блоке, в котором он определен, поэтому, покидая этот блок, литерал исчезает (например, переменная a
в примере выше), и вы остаетесь с обвисшим указатель.
По этой причине блоки обычно копируются в кучу для будущего использования. В коде, отличном от ARC, используются block_copy
и друзья. Копирование в кучу также фиксирует все релевантные переменные, используемые вашим блоком (которые могут создавать циклы сохранения).
На практике все это полностью избегает использования ARC, свойств и классов. Вы определяете свойство copy
в своем классе, а затем просто назначаете ему блоки. Если вы дадите компилятору генерировать геттер/сеттер, ваш блок-литерал будет автоматически скопирован в кучу.
@interface Bla : NSObject
@property (nonatomic, copy) void (^blockProperty)(int i);
@endf
...
Bla *bla = [[Bla alloc] init];
{
bla.blockProperty = ^(int i) { printf("%d", i); };
}
// bla.blockProperty now points to a heap copy of the block literal from above,
// so it not dangling.
Ответ 2
Я читал документацию на яблоках по блокам и делал немного больше исследований по этой части. Мне кажется, что с ARC второй примерный код полностью в порядке. Я не пробовал первый пример. Общая идея в принятом ответе правильная. Однако с ARC, когда вы назначаете литеральный блок (NSStackBlock) локальной переменной, блок копируется в кучу, и если вы проверите блок, вы увидите, что это действительно NSMallocBlock. Я также ссылался на этот блог на эту тему https://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html