Dealloc n'étant pas appelé sur l'application ARC

J'ai un UIViewController qui est poussé sur un controller de conteneur, puis retiré, et en utilisant l'instrument d'allocations, je peux voir que le controller de vue est détruit par la suite. Cependant, un point d'arrêt dans le dealloc du controller n'est jamais atteint. Est-ce que quelqu'un sait pourquoi le dealloc n'est pas appelé? Est-il possible pour ARC de détruire un object sans appeler le dealloc?

Aussi, j'ai désactivé NSZombies (certains ont dit que cela peut causer des problèmes de dealloc).

Modifier:

Dealloc ne fait pas grand chose, il imprime simplement sur la console, et il ne se fait jamais appeler:

- (void)dealloc { NSLog(@"Deallocating..."); }

Je ne peux pas afficher le controller de conteneur, c'est propriétaire et trop compliqué. Dealloc est appelé systématiquement sur certains controllers et pas d'autres. Si je peux find le time je vais essayer de postr une version simplifiée qui reproduit le problème.

Est-il possible de vérifier que NSZombies est désactivé?

Edit2

Je post une capture d'écran d'instruments; il me semble que c'est vraiment désaffecté.

entrez la description de l'image ici

Je viens de traverser un problème similaire. Avez-vous des blocs où vous faites reference à «soi»? J'avais des blocs pour l'observation des notifications dans mon init où je faisais reference à «self». Sous ARC, self est conservé dans les blocs. Mon dealloc n'était pas appelé et c'est là que je retirais l'observation.

L'astuce consiste à créer une reference __weak (iOS 5+) ou __unsafe_unretained (iOS 4.x) à votre 'self' et à l'utiliser pour accéder à soi-même ou à tout _iVars (ceux-ci provoqueront également le 'self') dans le bloc. Voici un exemple.

 __unsafe_unretained TableViewController *weakSelf = self; [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { if (weakSelf.tableView) { [weakSelf.tableView reloadData]; } }]; 

Dans mon cas c'était NSTimer . Il conserve sa cible, vous devez donc invalider la timer lorsque vous avez terminé avec le controller de vue.

Si dealloc n'est pas appelé par le VC, alors je parie qu'il y a une reference circulaire quelque part dans votre code, ce qui empêche ARC d'appeler dealloc.

Quelques choses à vérifier:

  1. Avez-vous un object instancié qui fait reference à la VC?
  2. Si vous avez besoin de referencer le VC, assurez-vous d'avoir utilisé l'atsortingbut '__unsafe_unretained' ou 'weak' (iOS5 +) afin que le cycle de conservation ne se produise pas.

J'ai été étouffé dans le cul quand les déclarations de mes delegates n'ont pas utilisé __unsafe_unretained.

Même avec ARC, vous pouvez inspecter le count de reference manuellement:

 CFIndex rc = CFGetRetainCount((__bridge CFTypeRef)myObj); 

Vous pouvez savoir avec certitude si votre code est bloqué dans un cycle de memory.

Mon problème était les delegates.

Vérifiez vos delegates! La propriété delegate doit avoir une valeur weak :

@property (weak, nonatomic) id<SomeProtocol> delegate;

Voici un autre conseil (qui m'est arrivé):

tl; dr: Regardez aussi vos variables d'instance de class, pas seulement les propriétés de class. Allouez-vous une variable d'instance dans le code, et ne la définissez pas à nil plus tard?

J'ai eu une class avec un tas de propriétés ( @property (nonatomic, strong) et @property (nonatomic, weak) ) dans son file d'en-tête. J'ai commenté ces propriétés une par une pour voir si cela va changer quelque chose. Il n'a pas. La class principale n'était toujours pas désaffectée. Donc le problème n'était pas dans les propriétés.

Ce que j'ai fait ensuite était de regarder les variables d'instance. J'ai eu une variable d'instance (qui était un UIViewController ), que j'ai créé sur viewDidLoad . Celui-ci n'a jamais été libéré!

Quand j'ai supprimé cette variable, bien sûr, ma class principale s'appelait dealloc.

Donc, parce que celui-ci n'a pas été libéré, ma class principale n'a pas été libérée non plus. Déplacer cette variable d'instance en tant que propriété a résolu le problème pour moi.

Question: Je ne suis pas sûr de savoir pourquoi cela arrive. Le operating system a-t-il un meilleur contrôle sur les propriétés d'une class que sur les variables d'instance? Il semble un peu étrange que la class parente qui contient la variable d'instance ne soit pas libérée à cause de sa variable d'instance.

Avez-vous NSZombieEnabled? Voir cette question:

Pourquoi l'object n'est-il pas libéré lors de l'utilisation de ARC + NSZombieEnabled

J'ai été perplexe par cela pendant un moment moi-même …