Цель C: где удалить наблюдателя для NSNotification?



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



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


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

478   14  

14 ответов:

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

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

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

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

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

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

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

Свифт

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)
    }
}

С

на 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];
    }
}

с 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

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

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

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

в swift используйте deinit, потому что dealloc недоступен:

deinit {
    ...
}

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

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

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

*edit: этот совет относится к iOS viewWillAppear и удаление в viewWillDisappear - однако Совет применяется, если по какой-то причине вы добавили наблюдателя в viewDidLoad)

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

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

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

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

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

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

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

ответ, на который я буду полагаться больше всего, я нашел в программировании iOS: Big Nerd Ranch Guide 4th. Я доверяю ребятам из БНР, потому что у них есть учебные центры iOS, и они не просто пишут еще одну поваренную книгу. Вероятно, в их интересах, чтобы быть точным.

БНР один пример: addObserver: на init:,removeObserver: на dealloc:

БНР пример второй:addObserver: на awakeFromNib:,removeObserver: на dealloc:

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

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

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

принятый ответ не является безопасным и может привести к утечке памяти. Пожалуйста, оставьте отмену регистрации в dealloc, но также отмените регистрацию в viewWillDisappear (это, конечно, если вы регистрируетесь в viewWillAppear)....ЭТО ТО, ЧТО Я СДЕЛАЛ В ЛЮБОМ СЛУЧАЕ, И ЭТО ОТЛИЧНО РАБОТАЕТ! :)

важно также отметить, что viewWillDisappear вызывается также, когда контроллер представления представляет новый UIView. Этот делегат просто указывает, что основной вид контроллера вида не отображается на дисплее.

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

в качестве решения я обычно удаляю наблюдателя в одном из этих двух методы:

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"viewController will disappear");
    if ([self isBeingDismissed]) {
        NSLog(@"viewController is being dismissed");
        [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
    }
}

-(void)dealloc {
    NSLog(@"viewController is being deallocated");
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}

по аналогичным причинам, когда я выдаю уведомление в первый раз, мне нужно учитывать тот факт, что в любое время вид с появляется над контроллером, то viewWillAppear метод срабатывает. Это, в свою очередь, создаст несколько копий одного и того же уведомления. Поскольку нет способа проверить, если уведомление уже активно, я устраняю проблему, удаляя уведомление перед его добавлением:

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"viewController will appear");
    // Add observers
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"imageGenerated" object:nil]; // This is added to avoid duplicate notifications when the view is presented again
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedImageFromCameraOrPhotolibraryMethodOnListener:) name:@"actionCompleted" object:nil];

}

SWIFT 3

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

в первом случае правильное место для добавления и удаления наблюдателя:

/// Add observers
///
/// - Parameter animated: the animation flag
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(...)
}

/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

для второго случая правильный путь:

/// Add observers
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(...)
}

/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if self.isBeingDismissed // remove only when view controller is removed disappear forever
    || !(self.navigationController?.viewControllers.contains(self) ?? true) {
        NotificationCenter.default.removeObserver(self)
    }
}

и никогда не ставить removeObserver на deinit{ ... } - это ошибка!

override func viewDidLoad() {   //add observer
  super.viewDidLoad()
  NotificationCenter.default.addObserver(self, selector:#selector(Yourclassname.method), name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}

override func viewWillDisappear(_ animated: Bool) {    //remove observer
    super.viewWillDisappear(true)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}

Comments

    Ничего не найдено.