Dealloc personnalisé et ARC (Objective-C)

208

Dans ma petite application iPad, j'ai une fonction de "changement de langue" qui utilise un observateur. Chaque contrôleur de vue s'enregistre auprès de mon observateur pendant son viewDidLoad:.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [observer registerObject:self];
}

Lorsque l'utilisateur appuie sur le bouton "changer de langue", la nouvelle langue est stockée dans mon modèle et l'observateur est averti et appelle un updateUi:sélecteur sur ses objets enregistrés.

Cela fonctionne très bien, sauf lorsque j'ai des contrôleurs de vue dans un TabBarController. En effet, lorsque la barre d'onglets se charge, elle récupère les icônes d'onglet de ses contrôleurs enfants sans initialiser les vues, elle viewDidLoad:n'est donc pas appelée, de sorte que ces contrôleurs de vue ne reçoivent pas de notifications de changement de langue. Pour cette raison, j'ai déplacé mes registerObject:appels dans la initméthode.

À l'époque où je viewDidLoad:m'inscrivais auprès de mon observateur, je me viewDidUnload:désinscrivais. Comme je m'inscris maintenant init, il est très logique de se désinscrire dealloc.

Mais voici mon problème. Quand j'écris:

- (void) dealloc
{
    [observer unregisterObject:self];
    [super dealloc];
}

Je reçois cette erreur:

L'ARC interdit l'envoi de message explicite de 'dealloc'

Puisque je dois appeler [super dealloc]pour m'assurer que les superclasses se nettoient correctement, mais ARC l'interdit, je suis maintenant bloqué. Existe-t-il un autre moyen de s'informer lorsque mon objet est en train de mourir?

Niku
la source
En remarque - une situation comme celle-ci peut provoquer une fuite de mémoire, qui ne s'afficherait pas dans l'outil Leaks. Si le dataModel conserve la référence à l'observateur (qui est la chose par défaut sous ARC, même pour les ivars), le dealloc ne sera jamais appelé, car le nombre de retenues sera supérieur à zéro. Ainsi, vous devrez peut-être désinscrire manuellement l'observateur pour permettre au dealloc d'être appelé en premier lieu.
Błażej Czapp
J'ai implémenté quelque chose de similaire pour les options pour droitiers et gauchers. Le seul VC qui a besoin du message est celui actuellement affiché. D'autres regardent le modèle dans viewDidLoad ou viewDidAppear pour apporter des modifications à l'interface. Peut-être que quelque chose comme ça fonctionnerait mieux.
Doug Watkins
@BlazejCzapp puisqu'il utilise un UITabBarController, et disons que l'UITabBarController contiendra toujours une référence au contrôleur enregistré (comme je suppose que c'est le cas avec ses contrôleurs `` enfants ''), la fuite de mémoire sera-t-elle toujours un problème? Je ne vois pas quand le contrôleur enregistré sera attribué. Merci
Objectif

Réponses:

419

Lorsque vous utilisez ARC, vous n'appelez simplement pas [super dealloc]explicitement - le compilateur le gère pour vous (comme décrit dans le document Clang LLVM ARC, chapitre 7.1.2 ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}
Justin
la source
4
Si la vue contient une référence à l'observateur, et l'observateur détient une référence à la vue, alors nous avons une référence circulaire. Le nombre de références de la vue est donc supérieur à 0 et deallocn'est jamais appelé. Est-il judicieux d'appeler [observer unregisterObject:self]en dealloc? Qu'est-ce que je rate?
user443854
c'est du travail. parce que l'observateur lui-même détient une référence au contrôleur. cela empêchera le dealloc d'être appelé en premier lieu
hasan