Удаление наблюдателя NSNotificationCenter в iOS 5 ARC

У меня есть проект на основе iOS 5 ARC, и у меня возникают трудности с тем, где я должен удалить наблюдателя для NSNotificationCenter наблюдений, которые я зарегистрировал в UIViewController. В аналогичных сообщениях на SO говорится, что это следует делать в методе -dealloc. Несмотря на то, что этот метод не требуется в проектах ARC, я добавил его с помощью следующего кода:

- (void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

В качестве теста я открываю UIViewController (внутри UINavigationController), делаю некоторые вещи, которые запускают уведомления, а затем извлекаю его из стека, нажав кнопку «Назад». Затем я снова открываю UIViewController и делаю еще кое-что, чтобы активировать уведомления, но замечаю, что каждый обратный вызов вызывается дважды — признак того, что предыдущие уведомления не были отменены. Повторение этой процедуры просто приводит к тому, что каждый обратный вызов вызывается более чем несколько раз, поэтому кажется, что они никогда не отменяют регистрацию.

Любая помощь будет оценена по достоинству!


person Skoota    schedule 04.12.2011    source источник
comment
У меня была такая же проблема - бесит. После нескольких часов отладки чистая + сборка «решила» проблему. Все это время я проходил через Dealloc и вызывал -removeObsever как на iPhone, так и на симуляторе. Так что, если кто-то еще увидит эту редкую проблему, сначала перестройте.   -  person emp    schedule 10.01.2012
comment
Как вы зарегистрировались в первую очередь? Вам нужно показать больше кода.   -  person matt    schedule 16.02.2012
comment
Сохраняет ли центр NSNotification наблюдателя?   -  person Nick Weaver    schedule 13.03.2012
comment
Фактически, Dealloc никогда не будет вызываться при использовании ARC. Это так, как задумано.   -  person Johan Karlsson    schedule 31.10.2014


Ответы (3)


Совершенно ясно, что ваш метод dealloc не вызывается (как и вызов removeObserver).

Почему бы не удалить наблюдателя вашего UIViewController в методах viewDidUnload: или viewWillDisappear:?

person Michael Dautermann    schedule 04.12.2011
comment
Насколько я знаю, viewDidUnload: вызывается только в условиях нехватки памяти. Мне также нужно, чтобы обратные вызовы уведомлений по-прежнему запускались, если представление находится за пределами экрана, а это означает, что я не могу использовать viewWillAppear: и viewWillDisappear: - person Skoota; 04.12.2011
comment
кстати, если вы извлекаете свой контроллер представления из стека, это должно освобождать его. Если это не так, что-то еще сохраняет ваш контроллер представления? Проверьте инструменты, чтобы быть уверенным. О, и вот связанный вопрос, который может быть вам полезен - person Michael Dautermann; 04.12.2011

Если ваш Dealloc не вызывается, это, вероятно, потому, что кто-то все еще держит ссылку на контроллер представления. Возможно, вам нужно пометить что-то как __weak? Вы можете использовать инструмент распределения, чтобы помочь отследить, что держится на вашем контроллере представления.

person Jesse Rusak    schedule 04.12.2011

«Мне также нужно, чтобы обратные вызовы уведомлений по-прежнему запускались, если представление находится за пределами экрана» -> вам может потребоваться зарегистрировать UIApplicationWillEnterForegroundNotification. Если это так, давайте попробуем это:

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"viewWillAppear");
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
}

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

- (void)applicationWillEnterForeground:(UIApplication *)application {
    NSLog(@"applicationWillEnterForeground");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    // do your stuff here
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"applicationDidEnterBackground");
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillEnterForeground:)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:nil];
}

Идея заключается в добавлении или удалении UIApplicationDidEnterBackgroundNotification всякий раз, когда вы входите и выходите из вашего экрана. Мы просто регистрируем UIApplicationWillEnterForegroundNotification, когда приложение переходит в фоновый режим, и удаляем его, когда оно возвращается. Обратите внимание, что мы просто удаляем UIApplicationDidEnterBackgroundNotification, когда viewWillDisappear.

Мой Dealloc() каким-то образом не вызывается, поэтому я нашел этот способ, надеюсь, он вам тоже пригодится.

Наслаждаться :)

person thanhbinh84    schedule 12.09.2012
comment
вы забыли позвонить [супер...] в тех. По документации. - person GregJaskiewicz; 21.11.2012
comment
Они обязательны? Я не вижу никаких проблем без них, так как я использую этот код в своем приложении. - person thanhbinh84; 22.11.2012
comment
Вы увидите проблему, когда суперобъект будет выполнять свои собственные действия. Возьмите за привычку делать это, потому что так говорит доктор. В противном случае однажды вы можете столкнуться со странными проблемами. - person GregJaskiewicz; 23.11.2012
comment
Спасибо, Грег, ты прав. Они упоминают в документе API developer.apple .com/library/ios/#documentation/uikit/reference/ - person thanhbinh84; 23.11.2012
comment
@doraemon Да, вы рано или поздно столкнетесь с проблемами, если не вызовете super в этих методах. На самом деле они делают какие-то магические вещи. Я видел несколько проблем, которые были решены путем добавления вызовов в super. - person Johan Karlsson; 31.10.2014
comment
Вместо добавления и удаления этих уведомлений, почему бы просто не добавить их в init или viewDidLoad и удалить всех наблюдателей в dealloc? Или, если вам действительно необходимо удалить их, когда представление исчезнет, ​​добавьте их оба в viewWillAppear и удалите в viewDidDisappear. Не надо жонглировать :) - person Chris Nolet; 22.11.2014