35 votes

Pourquoi l'objet n'est pas désalloué lors de l'utilisation d'ARC + NSZombieEnabled

J'ai converti mon application à l'ARC et a remarqué qu'un objet alloc ed dans l'une de mon point de vue, les contrôleurs n'était pas dealloc ed lors de ce point de vue contrôleur était dealloc ed. Il a fallu un certain temps à comprendre pourquoi. J'ai Activer Zombie Objets pour mon projet en cours de débogage et de ce qui s'est avéré être la cause. Considérons la suite de la logique d'application:

1) les Utilisateurs invoque l'action en RootViewController qui provoque un SecondaryViewController à être créé et présenté par presentModalViewController:animated.

2) SecondaryViewController contient un ActionsController c'est un NSObject sous-classe.

3) ActionsController observe une notification par NSNotificationCenter lorsqu'il est initialisé et s'arrête observe quand il est dealloc ed.

4) l'Utilisateur rejette SecondaryViewController de retour à l' RootViewController.

Avec Activer Zombie Objets éteint, le ci-dessus fonctionne très bien, tous les objets sont libérées. Avec Activer Zombie Objets sur ActionsController n'est pas libérée, même si SecondaryViewController est libéré.

Cela a causé des problèmes dans mon application b/c NSNotificationCenter continue à envoyer des notifications à l' ActionsController et les gestionnaires d'entraîner l'application crash.

J'ai créé une application simple pour illustrer ce à https://github.com/xjones/XJARCTestApp. Regardez le journal de la console avec Activer Zombie Objets on/off pour vérifier cela.

QUESTION(S)

  1. Est-ce comportement correct de l'Activer Zombie Objets?
  2. Comment dois-je mettre en œuvre ce type de logique pour éliminer le problème. Je voudrais continuer à utiliser Activer Zombie Objets.

EDIT #1: par Kevin suggestion, je l'ai soumis à Apple et à openradar http://openradar.appspot.com/10537635.

EDIT #2: précisions sur une bonne réponse

D'abord, je suis un développeur iOS expérimenté et je comprends parfaitement l'ARC, zombie objets, etc. Si je suis absent quelque chose, bien sûr, j'apprécie toute l'éclairage.

Ensuite, il est vrai qu'une solution de contournement pour ce crash est de supprimer actionsController en tant qu'observateur lors de l' secondaryViewController est libéré. J'ai trouvé aussi que si je définir explicitement actionsController = nil lorsque secondaryViewController est dealloc ed il sera dealloc ed. Ces deux ne sont pas grand contournement b/c, elles nécessitent l'utilisation de l'ARC mais le code que si vous n'êtes pas à l'aide de l'ARC (p. ex. néant iVars explicitement dans le dealloc). Une solution spécifique n'a pas également aider à identifier, si cela peut être un problème dans les autres contrôleurs de développeurs savent de façon déterministe quand/comment contourner ce problème.

Une bonne réponse serait d'expliquer comment la conception déterministe de savoir que vous besoin de faire quelque chose de spécial par rapport à un objet lors de l'utilisation de l'ARC + NSZombieEnabled de sorte qu'il permettrait de résoudre cet exemple précis et de s'appliquer de façon générale à un projet dans son ensemble, w/o en laissant le potentiel pour d'autres problèmes similaires.

Il est tout à fait possible qu'une bonne réponse n'existe pas car c'est peut être un bug dans XCode.

merci à tous!

9voto

danyowdee Points 3284

S'avère, j'ai écrit certains de graves bêtises

Si les zombies travaillé comme je l'ai d'abord écrit, en tournant sur zombies allait mener directement à d'innombrables faux positifs...

Il y a quelques isa-swizzling va, probablement en _objc_rootRelease, de sorte que toute dérogation dealloc doivent encore être appelé avec des zombies activé. La seule chose qui n'arrivera pas avec des zombies est l'appel à l' object_dispose - au moins pas par défaut.

Ce qui est drôle, c'est que, si vous faites un peu de journalisation, vous voyez que même avec de l'ARC est activé, votre mise en œuvre de l' dealloc fera appel à de la super-classe de mise en œuvre.

En réalité, j'étais en supposant que de ne pas voir ce à tous: depuis l'ARC génère ces funky .cxx_destruct méthodes pour se débarrasser de tout __strong ivars d'une classe, je m'attendais à voir cet appel de méthode dealloc - si il est mis en œuvre.

Apparemment, paramètre NSZombieEnabled de YES provoque .cxx_destruct de ne pas être appelée à tous - du moins, c'est ce qui s'est passé lorsque j'ai édité votre exemple de projet:
les zombies hors mène à la trace les deux deallocs, tandis que les zombies sur les rendements pas de trace pour un seul dealloc.

Si vous êtes intéressé, la journalisation supplémentaire est contenue dans une fourchette de l'exemple de projet - travaux en cours d'exécution juste: il y a deux partagé les régimes pour les zombies on/off.


D'origine (absurde) réponse:

Ce n'est pas un bug, mais une fonctionnalité.

Et il n'a rien à voir avec l'ARC.

NSZombieEnabled essentiellement swizzles dealloc pour une mise en œuvre qui, à son tour, l'isa-swizzles que le type de l'objet d' _NSZombie - un mannequin de classe qui explose, dès que vous envoyez un message pour elle. Ce comportement est normal et si je ne suis pas entièrement tort documenté.

7voto

0xced Points 10972

C'est un bogue qui a été reconnu par Apple dans les questions techniques QA1758 .

Vous pouvez contourner iOS 5 et OS X 10.7 en compilant ce code dans votre application:

 #import <objc/runtime.h>

@implementation NSObject (ARCZombie)

+ (void) load
{
    const char *NSZombieEnabled = getenv("NSZombieEnabled");
    if (NSZombieEnabled && tolower(NSZombieEnabled[0]) == 'y')
    {
        Method dealloc = class_getInstanceMethod(self, @selector(dealloc));
        Method arczombie_dealloc = class_getInstanceMethod(self, @selector(arczombie_dealloc));
        method_exchangeImplementations(dealloc, arczombie_dealloc);
    }
}

- (void) arczombie_dealloc
{
    Class aliveClass = object_getClass(self);
    [self arczombie_dealloc];
    Class zombieClass = object_getClass(self);

    object_setClass(self, aliveClass);
    objc_destructInstance(self);
    object_setClass(self, zombieClass);
}

@end
 

Vous trouverez plus d'informations sur cette solution de contournement dans mon article de blog Le débogage avec ARC et les zombis activés .

4voto

XJones Points 14327

Il s'avère que c'est un bogue iOS. Apple m'a contacté et a indiqué qu'il corrigeait cela dans iOS 6.

0voto

carbonbasednerd Points 132

pour répondre à la deuxième question, vous devez supprimer l'observateur de NSNotification, ce qui l'empêchera d'appeler la vue.

Normalement, vous le feriez dans le dealloc mais avec ce problème de zombies, on ne l'appelle peut-être pas. Peut-être pourriez-vous mettre cette logique dans viewDidUnload?

0voto

user501836 Points 411

Comme vous avez ouvert NSZombieEnabled, cela permet à l'objet de ne pas appeler dealloc et de placer l'objet à un emplacement spécial. vous pouvez fermer NSZombieEnabled et réessayer. Et revérifiez si votre code a la condition de rétention du cercle.

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