Из Переход к примечаниям к выпуску 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 больше не будет использоваться снова, а именно, когда истечет срок действия блока.