Почему мы должны устанавливать для переменной __block значение nil?

Из Переход к примечаниям к выпуску ARC

Используйте квалификаторы времени жизни, чтобы избежать циклов сильных ссылок

Вы можете использовать квалификаторы времени жизни, чтобы избежать циклов сильных ссылок. Для например, обычно, если у вас есть граф объектов, расположенных в иерархия родитель-потомок, и родители должны ссылаться на своих детей и наоборот, тогда вы укрепляете отношения между родителями и детьми. детско-родительские отношения слабые. Другие ситуации могут быть более тонкие, особенно когда они включают блочные объекты.

В ручном режиме подсчета ссылок __block id x;не удерживая x. В режиме ARC __block id x;по умолчанию сохраняет x(просто как и все другие значения). Чтобы получить режим ручного подсчета ссылок поведение в ARC, вы можете использовать __unsafe_unretained __block id x;. Однако, как следует из названия __unsafe_unretained, наличие несохраняемая переменная опасна (потому что может болтаться) и поэтому обескуражен. Два лучших варианта — использовать __weak(если вам не нужно поддерживать iOS 4 или OS X v10.6), или установите __block значение nil, чтобы разорвать цикл сохранения.

Итак, чем отличается переменная __block?

Почему здесь установлено значение nil? Сохраняется ли переменная __blockдважды? Кто держит все ссылки? Блок? Куча? Стек? Нить? Что?

Следующий фрагмент кода иллюстрирует эту проблему с помощью шаблона, который иногда используется при ручном подсчете ссылок.

MyViewController *myController = [[MyViewController alloc] init…];

// ...

myController.completionHandler =  ^(NSInteger result) {
   [myController dismissViewControllerAnimated:YES completion:nil];
};

[self presentViewController:myController animated:YES completion:^{
   [myController release];
}];

Как описано, вместо этого вы можете использовать квалификатор __blockи установить переменную myController в nilв обработчике завершения:

MyViewController * __block myController = [[MyViewController alloc] init…]; //Why use __block. my controller is not changed at all

// ...

myController.completionHandler =  ^(NSInteger result) {
    [myController dismissViewControllerAnimated:YES completion:nil];

    myController = nil; //Why set to nil here? Is __block variable retained twice? Who hold all the reference? The block? The heap? The stack? The thread? The what?
};

Также почему myControllerкомпилятор не устанавливает значение nil. Почему мы должны это делать? Кажется, что компилятор как бы знает, когда myController больше не будет использоваться снова, а именно, когда истечет срок действия блока.

6
задан user4951 12 June 2012 в 15:43
поделиться