Цель C: Где удалить наблюдателя для NSNotification? - PullRequest
97 голосов
/ 24 июня 2011

У меня есть объективный класс C. В нем я создал метод init и настроил в нем NSNotification

//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(getData)
                                             name:@"Answer Submitted"
                                           object:nil];

Где мне установить [[NSNotificationCenter defaultCenter] removeObserver:self] в этом классе? Я знаю, что для UIViewController я могу добавить его в метод viewDidUnload Так что же нужно сделать, если я только что создал целевой класс c?

Ответы [ 14 ]

111 голосов
/ 24 июня 2011

Общий ответ будет «как только вам больше не нужны уведомления». Это явно не удовлетворительный ответ.

Я бы рекомендовал добавить [notificationCenter removeObserver: self] в метод dealloc тех классов, которые вы намереваетесь использовать в качестве наблюдателей, поскольку это последний шанс полностью отменить регистрацию наблюдателя. Это, однако, защитит вас только от сбоев из-за уведомления центра о мертвых объектах. Он не может защитить ваш код от получения уведомлений, когда ваши объекты еще не находятся в состоянии, в котором они могут должным образом обрабатывать уведомления. Для этого ... См. Выше.

Редактировать (так как ответ, кажется, привлекает больше комментариев, чем я мог бы подумать) Все, что я пытаюсь сказать здесь: очень сложно дать общий совет относительно того, когда лучше удалить наблюдателя из центра уведомлений, потому что это зависит:

  • В вашем случае использования (Какие уведомления наблюдаются? Когда они отправляются?)
  • Реализация наблюдателя (Когда он готов к получению уведомлений? Когда он больше не готов?)
  • Предполагаемое время жизни наблюдателя (привязано ли оно к какому-либо другому объекту, скажем, представлению или контроллеру представления?)
  • ...

Итак, лучший общий совет, который я могу придумать: защитить ваше приложение. по крайней мере, с одной возможной неудачей, сделайте танец removeObserver: в dealloc, так как это последняя точка (в жизни объекта), где вы можете сделать это чисто. Это не означает, что «просто отложите удаление до вызова dealloc, и все будет хорошо». Вместо этого удалите наблюдателя , как только объект больше не будет готов (или необходим) для получения уведомлений . Это точный момент. К сожалению, не зная ответов на любой из упомянутых выше вопросов, я даже не могу догадаться, когда наступит этот момент.

Вы всегда можете безопасно removeObserver: объект несколько раз (и все, кроме самого первого вызова с данным наблюдателем, будут nops). Итак: подумайте о том, чтобы сделать это (снова) в dealloc просто для уверенности, но в первую очередь: сделайте это в соответствующий момент (что определяется вашим вариантом использования).

38 голосов
/ 11 апреля 2013

Примечание: это было проверено и работает на 100%

Swift

override func viewWillDisappear(animated: Bool){
    super.viewWillDisappear(animated)

    if self.navigationController!.viewControllers.contains(self) == false  //any other hierarchy compare if it contains self or not
    {
        // the view has been removed from the navigation stack or hierarchy, back is probably the cause
        // this will be slow with a large stack however.

        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

PresentedViewController

override func viewWillDisappear(animated: Bool){
    super.viewWillDisappear(animated)

    if self.isBeingDismissed()  //presented view controller
    {
        // remove observer here
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

Objective-C

ВiOS 6.0 > version, лучше удалить наблюдателя в viewWillDisappear, так как viewDidUnload устарел.

 [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];

Во много раз лучше remove observer, когда представление было удалено из navigation stack or hierarchy.

- (void)viewWillDisappear:(BOOL)animated{
 if (![[self.navigationController viewControllers] containsObject: self]) //any other hierarchy compare if it contains self or not
    {
        // the view has been removed from the navigation stack or hierarchy, back is probably the cause
        // this will be slow with a large stack however.

        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}

PresentedViewController

- (void)viewWillDisappear:(BOOL)animated{
    if ([self isBeingDismissed] == YES) ///presented view controller
    {
        // remove observer here
        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}
37 голосов
/ 24 апреля 2016

Начиная с iOS 9, больше не нужно удалять наблюдателей.

В OS X 10.11 и iOS 9.0 NSNotificationCenter и NSDistributedNotificationCenter больше не будет отправлять уведомления зарегистрированные наблюдатели, которые могут быть освобождены.

https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html#10_11NotificationCenter

25 голосов
/ 08 августа 2012

Если наблюдатель добавлен в контроллер вида , я настоятельно рекомендую добавить его в viewWillAppear и удалить его в viewWillDisappear.

18 голосов
/ 24 июня 2011
-(void) dealloc {
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}
8 голосов
/ 24 июня 2011

В общем, я положил его в метод dealloc.

7 голосов
/ 22 января 2015

При быстром использовании deinit, потому что dealloc недоступен:

deinit {
    ...
}

Swift документация:

Деинициализатор вызывается непосредственно перед тем, как экземпляр класса перераспределена. Вы пишете деинициализаторы с ключевым словом deinit, похоже как инициализаторы записываются с ключевым словом init. Deinitializers доступны только для типов классов.

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

5 голосов
/ 16 января 2013

По моему мнению, следующий код не имеет смысла в ARC :

- (void)dealloc
{
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}

В iOS 6 , также нет смысла удалять наблюдателей в viewDidUnload, потому что это устарело.

Подводя итог, я всегда делаю это в viewDidDisappear.Однако, это также зависит от ваших требований, как сказал @Dirk.

5 голосов
/ 25 ноября 2012

* edit: этот совет относится к iOS <= 5 (даже там вы должны добавить в <code>viewWillAppear и удалить в viewWillDisappear - однако совет применим, если по какой-то причине вы добавили наблюдателя в viewDidLoad)

Если вы добавили наблюдателя в viewDidLoad, вы должны удалить его как dealloc, так и viewDidUnload.В противном случае вы добавите его дважды, когда вызывается viewDidLoad после viewDidUnload (это произойдет после предупреждения о памяти).Это не обязательно в iOS 6, где viewDidUnload устарела и не будет вызываться (поскольку представления больше не выгружаются автоматически).

4 голосов
/ 13 июня 2014

Мне кажется, я нашел надежный ответ !Мне пришлось, так как ответы выше неоднозначны и кажутся противоречивыми.Я просмотрел кулинарные книги и руководства по программированию.

Во-первых, стиль addObserver: в viewWillAppear: и removeObserver: в viewWillDisappear: не работает для меня (я проверял это), потому что я отправляю уведомлениев дочернем контроллере представления для выполнения кода в родительском контроллере представления.Я бы использовал этот стиль, только если бы отправлял и слушал уведомления в том же контроллере представления.

Ответ, на который я буду больше всего полагаться, я нашел в Программировании на iOS: Руководство по ранчо для больших ботаников, 4-е.Я доверяю ребятам из BNR, потому что у них есть учебные центры для iOS, и они не просто пишут другую кулинарную книгу.Вероятно, в их интересах быть точными.

Пример BNR один: addObserver: в init:, removeObserver: in dealloc:

Пример BNR два: addObserver: inawakeFromNib:, removeObserver: в dealloc:

... при удалении наблюдателя в dealloc: они не используют [super dealloc];

Надеюсь, это поможет следующему человеку ...

Я обновляю этот пост, потому что Apple теперь почти полностью ушла со раскадровками, поэтому вышеупомянутое может не относиться ко всем ситуациям.Важная вещь (и причина, по которой я добавил этот пост в первую очередь) заключается в том, чтобы обратить внимание, если вам звонят viewWillDisappear:.Это было не для меня, когда приложение перешло в фоновый режим.

...