Добавление и удаление наблюдателей в NSNotificationCenter в UIViewController - программирование
Подтвердить что ты не робот

Добавление и удаление наблюдателей в NSNotificationCenter в UIViewController

Глядя на различные примеры Apple (например Добавить музыку), в которых я вижу, что они добавляют наблюдателей к умолчанию NSNotificationCenter в viewDidLoad, затем удалите их в dealloc. Это кажется опасным, поскольку viewDidLoad можно вызвать несколько раз без вызова dealloc. Затем это добавит один и тот же наблюдатель несколько раз, в результате чего обработчик будет вызван несколько раз.

Решением этого будет также удаление наблюдателей в viewDidUnload, но это означало бы, что один и тот же наблюдатель может быть удален во второй раз в dealloc, который кажется потенциальной проблемой.

Что мне не хватает?

4b9b3361

Ответ 1

Существует много дискуссий о правильном удалении уведомлений. Например:

Я предлагаю вам удалить наблюдателей в методах жизненного цикла viewWillDisappear (или viewDidDisappear) и viewDidUnload. (Примечание: viewDidUnload устарел и не должен быть реализован в iOS6 +, см. iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?)

Важное замечание:

viewDidUnload не может быть вызван - это не стандартный метод жизненного цикла.

От Apple doc:

viewDidUnload Когда возникает условие с низкой памятью и текущие контроллеры представления не нужны, система может выбрать удаление этих представлений из Память. Этот метод вызывается после просмотра вида контроллеров представления был выпущен и ваш шанс выполнить окончательную очистку.

Вместо этого dealloc вызывается всякий раз, когда количество ссылок для этого приемника равно нулю.

Надеюсь, что это поможет.

Edit

Для полноты вы можете увидеть эту ссылку о том, как avoid-nsnotification-removeobserver. Ссылка содержит некоторые полезные рекомендации по удалению наблюдателя (см. Также комментарии). Автор делает это в методах viewDidAppear/viewDidDisappear, поскольку viewWillAppear и viewWillDisappear не всегда корректно называются во многих приложениях. Это ваш выбор.

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

Ответ 2

Почему бы вам не сделать это в viewWillAppear/viewDidDisappear? Вы только заботитесь о уведомлениях, когда ваше представление показывается в любом случае, верно?

Ответ 3

- (void)viewWillAppear:(BOOL)animated
{
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self .........]
}

- (void)viewWillDisappear:(BOOL)animated
{
   [super viewWillDisappear:animated];
   [[NSNotificationCenter defaultCenter] removeObserver:self .........];
}

Ответ 4

Вы можете добавитьObserver в viewWillAppear и removeObserver в viewWillDisappear. но viewWillAppear может вызывать много раз. поэтому вы можете сначала удалить уведомление, а затем добавитьОбсервер.

 -(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:YES];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)name:@"UIKeyboardWillShowNotification"object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)name:@"UIKeyboardWillHideNotification"object:nil];
 }

 -(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:YES];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil];
 }