Контроллер вида dealloc не вызывается при использовании метода блока кода NSNotificationCenter с ARC
Когда я использую -addObserverForName: object: queue: usingBlock:
для NSNotificationCenter
в методе -viewDidLoad:
моего контроллера вида, метод -dealloc
не вызывается.
(Когда я удаляю -addObserverForName: object: queue: usingBlock:
, -dealloc
снова звонят.)
Использование -addObserver: selector: name: object:
, похоже, не имеет этой проблемы. Что я делаю не так? (Мой проект использует ARC.)
Ниже приведен пример моей реализации, на случай, если я делаю что-то не так:
[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
updateResult = YES;
}];
Заранее спасибо за любую помощь.
Я попытался добавить следующее (К no avail):
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
3 ответа:
Другими словами, у вас есть цикл удержания. Объект сохраняет блок, а блок сохраняет объект.
updateResult
является переменной экземпляра, которая не позволяет объекту быть освобожденным, поскольку он сохраняется этим блоком.Вам нужно будет создать слабую или небезопасную ссылку на этот экземпляр и его переменную для потери этой связи.
Перед блоком уведомлений добавьте следующее:
__unsafe_unretained YouObjectClass *weakSelf = self;
Или (в случае, если вы находитесь на iOS5 и выше)
__weak YouObjectClass *weakSelf = self;
Затем, внутри этого блока, ссылайтесь на объект через эту новую слабую ссылку:
[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result" object:nil queue:nil usingBlock:^(NSNotification *note) { weakSelf.updateResult = YES; }];
Пожалуйста, обратите внимание, что удерживающие циклы сами по себе не так уж плохи. Иногда вы действительно хотите, чтобы они произошли. Но это те случаи, когда вы уверены, что цикл будет прерван через определенное время (например, анимационные блоки). Цикл прерывается, как только блок выполнен и удален из стека.
Это очень вероятно, потому что у вас есть цикл удержания.
Это типичный случай, когда ваш блок неявно сохраняет самость, а самость сохраняет блок в некотором роде. У вас будет цикл удержания, поскольку каждый из них сохраняет другой, и их число удержания, таким образом, никогда не достигнет нуля.
Вы должны активировать предупреждение
Таким образом, в вашем случае вы используете переменную-Warc-retain-cycles
, которое предупредит вас о таких проблемах.updateResult
, которая, как я предполагаю, является переменной экземпляра, и это неявно сохранитьself
. Вместо этого вы должны использовать временную слабую переменную для представления себя и использовать ее в своем блоке, чтобы она не была сохранена, и вы разорвете цикл сохранения.__block __weak typeof(self) weakSelf = self; // weak reference to self, unretained by the block [[NSNotificationCenter defaultCenter] addObserverForName:@"Update result" object:nil queue:nil usingBlock:^(NSNotification *note) { // Use weakSelf explicitly to avoid the implicit usage of self and thus the retain cycle weakSelf->updateResult = YES; }];