Когда отписаться от NSNotification в UIView - PullRequest
15 голосов
/ 20 ноября 2011

Я использую следующие NSNotifications внутри UIView, чтобы представление могло быть уведомлено о появлении UIKeyboard и настроить его положение (фрейм) на экране:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];

Два вышеупомянутых уведомления подписываются в рамках метода -init UIView. Где лучше всего отказаться от подписки на эти уведомления после того, как представление исчезло за пределами экрана? В настоящий момент происходит сбой приложения каждый раз, когда UIKeyboard появляется в другом представлении, вероятно, потому что уведомление все еще отправляется в выпущенный тогда UIView.

Кроме того, есть ли лучшее место для подписки на уведомления, кроме метода -init?

Спасибо за любую помощь.

Ответы [ 7 ]

41 голосов
/ 20 ноября 2011

-[UIView willMoveToWindow:] и -[UIView didMoveToWindow] вызываются даже при удалении вида из окна. Аргумент окна (или свойство окна в случае -didMoveToWindow) в этом случае будет равен нулю, т.е. e.:

- (void)willMoveToWindow:(UIWindow *)newWindow {
    if (newWindow == nil) {
        // Will be removed from window, similar to -viewDidUnload.
        // Unsubscribe from any notifications here.
    }
}

- (void)didMoveToWindow {
    if (self.window) {
        // Added to a window, similar to -viewDidLoad.
        // Subscribe to notifications here.
    }
}

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

4 голосов
/ 20 ноября 2011

Я положил removeObserver: звонки -dealloc.

У меня до сих пор не было проблем.

2 голосов
/ 20 ноября 2011

Окончательный ответ (например, убедитесь, что объект больше не является ссылкой на NSNotificationCenter, когда заканчивается его жизненный цикл) должен сделать, как предлагает @Tom, и удалить себя в качестве наблюдателя в dealloc.

.субъективный ответ - это также хорошая практика, чтобы прекратить наблюдение, когда уведомления больше не относятся к объекту.Это зависит только от вас, чтобы решить на основе дизайна вашего приложения.Например, если у вас есть просмотры, которые остаются живыми, но входят и выходят из вида, вы можете решить начать наблюдение, когда они добавляются в подпредставление, и прекратить наблюдение, когда они удалены.проживать (в сравнении с контроллером), это также зависит от вас, очевидно, это может работать в обоих направлениях.Я бы принял решение исходя из обстоятельств.Если для обработки уведомления в представлении требуется вставить логику приложения в представление (т. Е. Обработать представление как контроллер), тогда это красный флаг.

1 голос
/ 20 ноября 2011

Во-первых, вы должны учитывать, когда вы хотите прекратить получать уведомления:

  1. Когда представление освобождается
  2. Когда представление исчезает

Вы должнывсегда проверяйте, видит ли ваш вид уведомления и звоните -removeObserver: в -dealloc.Кроме того, если вы рассматриваете 2, переопределите -viewWillDisappear или -viewDidDisappear или любую другую точку, где вы управляете иерархией представления UIViewController представления.

Я рекомендую вам поместить логику в UIViewController, потому что с точки зрения отношений UIView не делаетНе владеть своей рамой.

0 голосов
/ 20 ноября 2011

В качестве практики для уведомлений клавиатуры я обычно использую

addObserver

в

viewWillAppear

и

removeObserver

в

viewWillDisAppear

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

0 голосов
/ 20 ноября 2011

Вы можете создать отдельную функцию для добавления и удаления наблюдений, а затем позже вы можете все эти функции из экземпляра представления.Кстати, для ответа на ваш вопрос я бы удалил наблюдателей перед тем, как удалить само представление из суперпредставления.Я надеюсь, вы понимаете.

0 голосов
/ 20 ноября 2011

Чтобы отписаться, вы можете использовать

- (void)removeObserver:(id)notificationObserver

или

- (void)removeObserver:(id)notificationObserver name:(NSString *)notificationName object:(id)notificationSender

Оба метода являются NSNotificationCenter методами экземпляра.

Взгляните на Ссылка класса NSNotificationCenter

...