104 votes

Objective-C : Où supprimer l'observateur pour NSNotification ?

J'ai une classe Objective C. En elle, j'ai créé une méthode init et mis en place une NSNotification dedans

//Mettre en place la NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(getData)
                                             name:@"Answer Submitted"
                                           object:nil];

Où dois-je mettre le [[NSNotificationCenter defaultCenter] removeObserver:self] dans cette classe? Je sais que pour un UIViewController, je peux l'ajouter dans la méthode viewDidUnload. Que faut-il faire si j'ai juste créé une classe objective c?

0 votes

J'ai mis cela dans la méthode dealloc.

1 votes

La méthode de désallocation n'a pas été automatiquement créée pour moi lorsque j'ai créé la classe objective c, donc c'est bon pour moi de l'ajouter ?

0 votes

Oui, vous pouvez implémenter -(void)dealloc et ensuite ajouter removeObserser:self dedans. C'est la manière la plus recommandée de mettre removeObservers:self

113voto

Dirk Points 17809

La réponse générique serait "dès que vous n'avez plus besoin des notifications". Cependant, ce n'est évidemment pas une réponse satisfaisante.

Je recommanderais d'ajouter un appel [notificationCenter removeObserver: self] dans la méthode dealloc de ces classes, que vous prévoyez d'utiliser en tant qu'observateurs, car c'est la dernière chance de désinscrire proprement un observateur. Cela vous protégera cependant uniquement contre les plantages dus au centre de notifications notifiant des objets morts. Cela ne protège pas votre code contre la réception de notifications lorsque vos objets ne sont pas encore ou ne sont plus dans un état dans lequel ils peuvent correctement gérer la notification. Pour cela... Voir ci-dessus.

Édition (puisque la réponse semble susciter plus de commentaires que je ne l'aurais pensé) Tout ce que j'essaie de dire ici, c'est que c'est vraiment difficile de donner des conseils généraux sur le moment idéal pour retirer l'observateur du centre de notifications, car cela dépend de :

  • Votre cas d'utilisation (quelles notifications sont observées ? Quand sont-elles envoyées ?)
  • L'implémentation de l'observateur (quand est-il prêt à recevoir des notifications ? Quand ne l'est-il plus ?)
  • La durée de vie prévue de l'observateur (est-il lié à un autre objet, par exemple, une vue ou un contrôleur de vue ?)
  • ...

Donc, le meilleur conseil général que je puisse donner est : pour protéger votre application contre au moins une défaillance possible, faites la danse de removeObserver: dans dealloc, car c'est le dernier point (dans la vie de l'objet) où vous pouvez le faire proprement. Cela ne signifie pas : "reportez simplement le retrait jusqu'à ce que dealloc soit appelé, et tout ira bien". Au contraire, retirez l'observateur dès que l'objet n'est plus prêt (ou nécessaire) à recevoir des notifications. C'est le moment exact. Malheureusement, sans connaître les réponses à l'une des questions mentionnées ci-dessus, je ne peux même pas deviner quand ce moment serait.

Vous pouvez toujours removeObserver: un objet plusieurs fois (et tous les appels sauf le tout premier avec un observateur donné seront inopérants). Donc : envisagez de le faire (encore) dans dealloc juste pour être sûr, mais avant tout : faites-le au moment approprié (qui est déterminé par votre cas d'utilisation).

4 votes

Ceci n'est pas sûr avec ARC et pourrait potentiellement causer une fuite. Voir cette discussion : cocoabuilder.com/archive/cocoa/311831-arc-and-dealloc.html

3 votes

@MobileMon L'article que vous avez partagé semble confirmer mon point de vue. Qu'est-ce que j'ai raté ?

0 votes

Je suppose qu'il convient de noter qu'il faut retirer l'observateur quelque part ailleurs que dans dealloc. Par exemple, viewwilldisappear

39voto

Prince Points 16165

Note : Ceci a été testé et fonctionne à 100%

Swift

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

    if self.navigationController!.viewControllers.contains(self) == false  //tout autre hiérarchie compare si elle contient ou non self
    {
        // la vue a été supprimée de la pile de navigation ou de la hiérarchie, le retour est probablement la cause
        // cela sera lent avec une grande pile cependant.

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

ViewController Présenté :

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

    if self.isBeingDismissed()  //contrôleur de vue présenté
    {
        // supprimer l'observateur ici
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

Objective-C

Dans la version iOS 6.0 > , il est préférable de supprimer l'observateur dans la méthode viewWillDisappear car la méthode viewDidUnload est obsolète.

 [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];

Il est souvent préférable de supprimer l'observateur lorsque la vue a été retirée de la pile de navigation ou de la hiérarchie.

- (void)viewWillDisappear:(BOOL)animated{
 if (![[self.navigationController viewControllers] containsObject: self]) //tout autre hiérarchie compare si elle contient ou non self
    {
        // la vue a été supprimée de la pile de navigation ou de la hiérarchie, le retour est probablement la cause
        // cela sera lent avec une grande pile cependant.

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

ViewController Présenté :

- (void)viewWillDisappear:(BOOL)animated{
    if ([self isBeingDismissed] == YES) /// contrôleur de vue présenté
    {
        // supprimer l'observateur ici
        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}

8 votes

Sauf si un contrôleur souhaite toujours des notifications lorsque sa vue n'est pas affichée (par exemple, pour recharger un tableView).

2 votes

@wcochran recharge automatiquement dans viewWillAppear:

0 votes

@Prince pouvez-vous expliquer pourquoi viewWillDisappear est meilleur que dealloc? Donc nous avons ajouté un observateur à self, donc lorsque self sera supprimé de la mémoire, il appellera dealloc et alors tous les observateurs seront supprimés, n'est-ce pas une bonne logique.

25voto

RickiG Points 6348

Si l'observateur est ajouté à un contrôleur de vue, je recommande fortement de l'ajouter dans viewWillAppear et de le supprimer dans viewWillDisappear.

0 votes

Je suis curieux, @RickiG: pourquoi recommandez-vous d'utiliser viewWillAppear et viewWillDisappear pour les viewControllers ?

2 votes

@IsaacOveracker quelques raisons: votre code de configuration (par ex. loadView et viewDidLoad) pourrait potentiellement provoquer le déclenchement des notifications et votre contrôleur doit en tenir compte avant de s'afficher. Si vous le faites de cette manière, il y a quelques avantages. Pour l'instant, vous avez décidé de "quitter" le contrôleur, vous ne vous souciez pas des notifications et elles ne vous obligent pas à faire de la logique pendant que le contrôleur est poussé hors de l'écran etc. Il y a des cas particuliers où le contrôleur devrait recevoir des notifications lorsqu'il est hors écran, je suppose que vous ne pouvez pas le faire. Mais des événements comme celui-ci devraient probablement être dans votre modèle.

1 votes

@IsaacOveracker aussi avec ARC, il serait étrange d'implémenter dealloc pour se désabonner des notifications.

20voto

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

4 votes

Je changerais l'ordre de ces instructions... Utiliser self après [super dealloc] me rend nerveux... (même si le receveur est peu susceptible de désallouer le pointeur de quelque manière que ce soit, eh bien, on ne sait jamais, comment ils ont implémenté NSNotificationCenter)

0 votes

Hm. cela a fonctionné pour moi. Avez-vous remarqué un comportement inhabituel ?

0 votes

Non. Il s'agissait simplement d'une remarque générale. Cela me semble juste comme utiliser un pointeur malloc après l'appel à free...

7voto

Raphael Petegrosso Points 2009

En général, je le mets dans la méthode dealloc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X