Я не знаю, какие шаблоны блока я должен избегать для литеральной области в 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