9

У меня есть код с явным эталонным циклом в блоке ivar. Следующий код вызывает опорный цикл и dealloc никогда не называют:__block self reference cycle в блоке ivar в ARC

__block MyViewController *blockSelf = self; 

loggedInCallback = ^(BOOL success, NSError *error){ 
    if (success) 
    { 
     double delayInSeconds = 1.0; 
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void) 
     { 
      [blockSelf.delegate loginDidFinish]; 
     });    
    } 
}; 

Однако, если я создаю другую __block переменные для ссылки на мой делегат области видимости блока для захвата, опорный цикл уходит:

__block id <MyViewControllerDelegate> blockDelegate = self.delegate; 

loggedInCallback = ^(BOOL success, NSError *error){ 
    if (success) 
    { 
     double delayInSeconds = 1.0; 
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void) 
     { 
      [blockDelegate loginDidFinish]; 
     });    
    } 
}; 

Просто хочу понять, что здесь происходит.

ответ

16

Я собираюсь предположить, что вы используете ARC здесь. До ARC ваш первый пример будет работать нормально. С ARC семантика __block изменилась. __block декларации теперь сильно захвачены, а не слабо. Замените __block на __weak в вашем первом образце, и все должно работать должным образом.

Что касается второго примера, вы создаете сильную ссылку на делегата, но у вас нет ссылки на ваш объект. Таким образом, нет цикла, и все счастливы.

Я рекомендую прочитать статью Майка Эша на изменениях, внесенных в АРК, особенно вокруг блока захвата и __weakhttp://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

+0

Отлично, спасибо! Я обновил заголовок моего вопроса, чтобы быть более наглядным. –

+1

Я ориентируюсь на iOS 4.3, поэтому мне пришлось использовать '' __unsafe_unretained'', но это работает, спасибо! –

Смежные вопросы