NSNotificationCenter в отношении ViewWillAppear и ViewWillDisapper

У меня есть простой viewController, который я хочу прослушать UIKeyboardWillHideNotification. Поэтому у меня есть следующий код:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void) keyboardWillBeHidden
{
    [self.scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}

Я пытаюсь решить, когда удалить viewController в качестве наблюдателя центра уведомлений. Мне нужно знать о UIKeyboardWillHideNotification только тогда, когда на экране отображается контроллер представления, поэтому я думаю о добавлении следующего:

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

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


person Nosrettap    schedule 30.03.2013    source источник
comment
Почему бы не удалить Observer в dealloc?   -  person Anoop Vaidya    schedule 30.03.2013
comment
Я мог бы, но это кажется чрезмерным, учитывая, что мне не нужно знать об уведомлениях, когда контроллер просмотра находится за пределами экрана.   -  person Nosrettap    schedule 30.03.2013


Ответы (2)


Регистрация уведомления в viewWillAppear и отмена регистрации в viewWillDisappear кажется мне чистым и симметричным решением.

Обратите внимание, что viewWillAppear может вызываться несколько раз перед dealloc (например, если другой контроллер представления помещен в ваш VC, или если вы переключаетесь между контроллерами панели вкладок). Если вы зарегистрируете уведомление в viewWillAppear и отмените его регистрацию только в dealloc, вы получите дубликат регистрации (сравните Предупреждение для пользователей iOS / iPhone о повторяющихся наблюдениях NSNotification), а зарегистрированный селектор вызывается несколько раз для одного события уведомления.

На самом деле я предпочитаю блочный метод регистрации наблюдателя.

addObserverForName:object:queue:usingBlock:

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

person Martin R    schedule 30.03.2013
comment
Итак, когда вы используете метод addObserverForName, я бы все равно поместил его в viewWillAppear и viewWillDisapper? - person Nosrettap; 30.03.2013
comment
@Nosrettap: Да. Так что в данном случае это не имеет большого значения, я просто упомянул это как общее замечание для более сложных ситуаций. И мне нравятся блочные методы! - person Martin R; 30.03.2013
comment
@MartinR у вас есть пример реализации с addObserverForName:object:queue:usingBlock:? Огромное спасибо - person Ríomhaire; 05.05.2016

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

dealloc будет вызываться только тогда, когда не останется сильных указателей, указывающих на ваш viewController.

Как предлагает Ануп Вайдья, вполне выполнимо поместить removeObserver в dealloc и быть уверенным, что dealloc не будет вызван, пока ваш viewController находится на экране, а если это произойдет ... ну, у вас гораздо большие проблемы, чем удаление наблюдателя

Изменить: поскольку я еще не могу ответить на комментарии, когда ваш viewController отключен от экрана, он фактически освобожден. Затем он повторно создается при вызове на экране.

Изменить: я ошибаюсь

person Pinwheeler    schedule 30.03.2013
comment
Контроллер представления не автоматически освобождается и повторно создается, когда он находится вне экрана. Также вполне возможно освободить контроллер представления, когда его представление находится на экране, потому что представление не имеет четкой ссылки на его контроллер представления. Обычно этого не должно происходить, особенно с ARC, но если вы вручную добавляете представление vc в иерархию, это может произойти довольно легко, если vc автоматически выпускается. - person omz; 30.03.2013
comment
@omz: Мне не понятно ваше второе предложение. Как могло случиться, что контроллер представления был освобожден, пока его представление все еще отображается? Разве не должно быть сильных ссылок на контроллер представления, пока он находится где-то в иерархии контроллеров представления? - Хорошо, я только что видел ваше обновление к комментарию. Я думал только о ARC. - person Martin R; 30.03.2013
comment
О, плохо, я думал, что слышал это на лекциях в Стэнфорде, но я все еще в основном нуб - person Pinwheeler; 31.03.2013