Question

Je suis nouveau dans le développement iPhone et le XCode en général et je ne sais pas comment commencer à résoudre le problème d'un signal EXC_BAD_ACCESS . Comment puis-je faire en sorte que XCode se brise sur la ligne exacte à l'origine de l'erreur?

Je n'arrive pas à faire arrêter XCode sur la ligne à l'origine du problème, mais je vois les lignes suivantes dans ma console de débogage:

  

dim. 25 15:12:14 jasonsmacbook   TestProject [1289]:   CGContextSetStrokeColorWithColor:   contexte invalide

     

dim. 25 15:12:14 jasonsmacbook   TestProject [1289]:   CGContextSetLineWidth: contexte invalide

     

dim. 25 15:12:14 jasonsmacbook   TestProject [1289]:   CGContextAddPath: contexte invalide

     

dim. 25 15:12:14 jasonsmacbook   TestProject [1289]:   CGContextDrawPath: contexte invalide

     

2009-10-25 15: 12: 14.680   LanderTest [1289: 207] *** - [CFArray   objectAtIndex:]: message envoyé à   instance désallouée 0x3c4e610

Maintenant, j'essaie de dessiner le contexte que je récupère dans UIGraphicsGetCurrentContext () et de le transmettre à l'objet avec lequel je souhaite dessiner.

Après des essais et des erreurs de débogage, j'ai constaté qu'un NSMutableArray pour lequel j'ai une propriété de ma classe était un zombie. Je suis entré dans la fonction init de la classe et voici le code que j'utilisais:

if ((self = [super init])) {
        NSMutableArray *array = [NSMutableArray array];
        self.terrainBlocks = array;
        [array release];
    }
    return self;    
}

J'ai supprimé la ligne [publication du tableau] et elle ne me donne plus le signal EXC_BAD_ACCESS , mais je ne comprends plus pourquoi cela fonctionne. Je pensais que lorsque j'utilisais la propriété, elle la conservait automatiquement pour moi. Je devais donc la libérer de init afin d'éviter toute fuite. Je ne comprends vraiment pas comment cela fonctionne et tous les guides et les questions Stackoverflow que j'ai lus ne font que me confondre davantage avec la façon de définir les propriétés dans ma méthode init. Il ne semble pas y avoir de consensus sur la meilleure solution.

Était-ce utile?

La solution

Pour toute erreur EXC_BAD_ACCESS, vous essayez généralement d'envoyer un message à un objet validé. Le MEILLEUR moyen de les localiser consiste à utiliser NSZombieEnabled .

Cela fonctionne en ne lâchant jamais réellement un objet, mais en l'enveloppant comme un "zombie". et mettre un drapeau à l'intérieur qui dit qu'il aurait normalement été libéré. De cette façon, si vous essayez d'y accéder à nouveau, il sait toujours ce que c'était avant de commettre l'erreur, et avec ce peu d'informations, vous pouvez généralement revenir en arrière pour voir quel était le problème.

Cela est particulièrement utile dans les threads d'arrière-plan lorsque le débogueur recherche parfois des informations utiles.

TRÈS IMPORTANT À NOTER , vous devez toutefois vous assurer à 100% que cela ne figure que dans votre code de débogage et non dans votre code de distribution. Parce que rien n'est jamais publié, votre application va fuir et fuite et fuite. Pour me rappeler de le faire, je mets ce journal dans mon appdélégué:

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
  NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");

Si vous avez besoin d'aide pour trouver la ligne exacte, effectuez un build-et-débogage ( CMD-Y ) au lieu d'un build-and-run ( CMD-R ). Lorsque l'application se bloque, le débogueur vous indiquera exactement quelle ligne et en combinaison avec NSZombieEnabled, vous devriez être en mesure de savoir exactement pourquoi.

Autres conseils

À propos de votre tableau. La ligne

NSMutableArray *array = [NSMutableArray array];

ne vous donne pas réellement un objet conservé, mais plutôt un objet autorelease. Il est probablement conservé à la ligne suivante, mais vous ne devez pas le publier à la troisième ligne. Voir this

  

Telle est la règle fondamentale:

     
    

Vous devenez propriétaire d'un objet si vous le créez à l'aide d'une méthode dont le nom commence par «alloc» ou «nouveau» ou contient «copie» (par exemple, alloc, newObject ou mutableCopy), ou si vous lui envoyez une conserver le message. Vous êtes responsable de la renonciation à la propriété des objets que vous possédez via release ou autorelease. À tout autre moment où vous recevez un objet, vous ne devez pas le libérer.

  

Dans Xcode 4, vous pouvez activer les zombies en cliquant sur la liste déroulante Schéma (en haut à gauche, à droite du bouton d'arrêt) - > Modifier le schéma - > Onglet Diagnostics - > Activer les objets zombies

Xcode / gdb se casse toujours sur EXC_BAD_ACCESS , il vous suffit de remonter la pile d'appels pour trouver le code qui l'a déclenché.

Notez que ce type d'erreur se produit souvent avec les objets autoreleased , ce qui signifie que la cause ultime du problème ne se trouvera pas dans la pile d'appels ayant déclenché EXC_BAD_ACCESS . C'est à ce moment que NSZombieEnabled et NSAutoreleaseFreedObjectCheckEnabled deviennent utiles.

Nouvelle réponse à un ancien fil de discussion ... dans XCode 4, le moyen le plus efficace de diagnostiquer les exceptions EXC_BAD_ACCESS consiste à utiliser Instruments pour profiler votre application (dans XCode, cliquez sur Produit / Profil et choisissez Zombies). Cela vous aidera à identifier les messages envoyés aux objets désalloués.

Dans les classes Stanford CS193P: si vous ajoutez un point d'arrêt (manuellement, en modifiant des points d'arrêt) pour le symbole objc_exception_throw , vous pouvez obtenir une bien meilleure image de ce qui a mal tourné - en laissant les choses se dérouler jusqu'au point. où le débogueur s’arrête tout seul a tendance à obscurcir les choses et à bousiller la trace de pile. Lorsque vous vous arrêtez dans objc_exception_throw, vous pouvez souvent regarder en arrière pour savoir quel accès / opération a causé votre problème.

Une autre approche utile consiste à définir des points d'arrêt qui se déclencheront directement après la survenue de l'exception:

  

Ouvrez la fenêtre des points d'arrêt (Exécuter - Afficher - Points d'arrêt) et ajoutez deux points d'arrêt symboliques appelés «objc_exception_throw» et «[NSException raise] "

De: http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/

Je voulais juste ajouter pour les autres qui viennent d'un site Web, à la recherche de solutions pour la même erreur mais avec une erreur différente. Dans mon cas, la même erreur s'est produite lorsque j'ai tenté d'instancier NSDictionary avec une faute de frappe dans le nom de la clé, là où j'ai oublié d'ajouter "@". devant ma clé:

NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];

J'espère que je n'ai pas manqué de réponse identique, mais j'ai constaté qu'il était possible pour certains projets de générer cette erreur en raison de l'exécution sur des simulateurs d'anciennes versions d'iOS pouvant être incompatibles avec une dépendance de projet ou un framework. Je poursuivais trop longtemps l'un de ces objectifs avant de réaliser que cela se produisait dans les versions du simulateur d'empilement, comme l'iPhone 4S, que l'application n'était même pas censée essayer de la prendre en charge.

Cela aurait été bien d’avoir reçu un message d’erreur plus détaillé, mais j’imagine que c’est la responsabilité du cadre dans lequel il a été créé. aussi mal que je me suis retrouvé.

Avant d’activer les zombies, je vous recommande de vous débarrasser de tous les avertissements (si vous en avez). Des choses simples comme une fonction non vide sans return peuvent être à l'origine de cette erreur. Si vous n'avez pas d'avertissements, procédez comme le suggèrent les autres réponses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top