web-dev-qa-db-fra.com

Signal EXC_BAD_ACCESS reçu

Lors du déploiement de l'application sur le périphérique, le programme se ferme après quelques cycles avec l'erreur suivante:

Program received signal: "EXC_BAD_ACCESS".

Le programme fonctionne sans aucun problème sur le simulateur iPhone, il sera également débogué et exécuté aussi longtemps que je parcourrai les instructions une par une. Dès que je le laisserai fonctionner à nouveau, je frapperai le signal EXC_BAD_ACCESS.

Dans ce cas particulier, il s’agissait d’une erreur dans le code de l’accéléromètre. Il ne s’exécuterait pas dans le simulateur, c’est pourquoi il n’a généré aucune erreur. Cependant, il s'exécuterait une fois déployé sur le périphérique.

La plupart des réponses à cette question traitent de l'erreur générale EXC_BAD_ACCESS, aussi je vais laisser cette question ouverte en tant que fourre-tout pour l'erreur redoutée de mauvais accès.

EXC_BAD_ACCESS est généralement émis à la suite d'un accès illégal à la mémoire. Vous pouvez trouver plus d'informations dans les réponses ci-dessous.

Avez-vous déjà rencontré le signal EXC_BAD_ACCESS et comment l'avez-vous géré?

281
Héctor Ramos

De votre description, je soupçonne que l'explication la plus probable est que vous avez une erreur dans votre gestion de mémoire. Vous avez indiqué que vous travailliez sur le développement de l'iPhone depuis quelques semaines, mais que vous sachiez si vous étiez expérimenté avec Objective C en général. Si vous venez d'un autre milieu, il faut parfois un peu de temps avant d'internaliser véritablement les règles de gestion de la mémoire, à moins que vous en fassiez le point.

N'oubliez pas que tout ce que vous obtenez d'une fonction d'allocation (généralement la méthode alloc statique, mais il y en a quelques autres), ou une méthode de copie, vous appartient également à la mémoire et devez la libérer lorsque vous avez terminé.

Mais si vous récupérez quelque chose à partir de n'importe quoi d'autre y compris les méthodes d'usine (par exemple [NSString stringWithFormat]), vous aurez alors une référence autorelease, ce qui signifie qu'elle pourrait être diffusée ultérieurement. par un autre code - il est donc essentiel que si vous avez besoin de le garder au-delà de la fonction immédiate, vous le conserviez. Si vous ne le faites pas, la mémoire peut rester allouée pendant que vous l'utilisez, ou être libérée mais elle est toujours valide lors des tests de votre émulateur, mais elle risque davantage d'être libérée et de se présenter comme une erreur d'accès erronée lors de son exécution sur le périphérique.

La meilleure façon de localiser ces problèmes et une bonne idée (malgré tout, même en l'absence de problèmes apparents) consiste à exécuter l'application dans l'outil Instruments, en particulier avec l'option Fuites.

193
philsquared

Une cause majeure de EXC_BAD_ACCESS est liée à la tentative d’accès aux objets validés.

Pour savoir comment résoudre ce problème, lisez ce document: DebuggingAutoReleasePool

Même si vous ne pensez pas que vous "libérez des objets libérés automatiquement", cela s'appliquera à vous.

Cette méthode fonctionne extrêmement bien. Je l'utilise tout le temps avec grand succès !!

En résumé, cela explique comment utiliser la classe de débogage NSZombie de Cocoa et l'outil "malloc_history" en ligne de commande pour rechercher exactement quel objet publié a été utilisé dans votre code.

Note:

L'exécution d'instruments et la recherche de fuites n'aideront pas à dépanner EXC_BAD_ACCESS. Je suis presque sûr que les fuites de mémoire n'ont rien à voir avec EXC_BAD_ACCESS. La définition d'une fuite est un objet auquel vous n'avez plus accès et vous ne pouvez donc pas l'appeler.

UPDATE: J'utilise maintenant Instruments pour déboguer les fuites. À partir de Xcode 4.2, choisissez Produit-> Profil et, lorsque vous lancez Instruments, choisissez "Zombies".

99
bentford

Un signal EXC_BAD_ACCESS est le résultat du passage d'un pointeur non valide à un appel système. J'en ai reçu un peu plus tôt aujourd'hui avec un programme de test sous OS X. Je passais une variable non initialisée à pthread_join(), qui était due à une faute de frappe antérieure.

Je ne suis pas familier avec le développement sur iPhone, mais vous devriez revérifier tous vos pointeurs de mémoire tampon que vous passez aux appels système. Augmentez le niveau d'avertissement de votre compilateur jusqu'au bout (avec gcc, utilisez les options -Wall et -Wextra). Activez autant de diagnostics que possible sur le simulateur/débogueur.

12
Adam Rosenfield

D'après mon expérience, cela est généralement dû à un accès mémoire illégal. Vérifiez tous les pointeurs, en particulier les pointeurs d'objet, pour vous assurer qu'ils sont initialisés. Assurez-vous que votre fichier MainWindow.xib, si vous en utilisez un, est configuré correctement, avec toutes les connexions nécessaires.

Si aucune de ces vérifications sur papier ne révèle rien et que cela ne se produit pas en mode pas à pas, essayez de localiser l'erreur avec les instructions NSLog (): saupoudrez votre code avec elles, en les déplaçant jusqu'à ce que vous isoliez la ligne qui en est la cause. l'erreur. Puis définissez un point d'arrêt sur cette ligne et exécutez votre programme. Lorsque vous atteignez le point d'arrêt, examinez toutes les variables et les objets qu'ils contiennent pour voir si quelque chose ne ressemble pas à ce à quoi vous vous attendiez. Je ferais particulièrement attention aux variables dont la classe d'objet correspond à quelque chose d'inattendu. Si une variable est supposée contenir une UIWindow mais qu'elle contient plutôt une NSNotification, la même erreur de code sous-jacent pourrait se manifester de manière différente lorsque le débogueur n'est pas en opération.

8
Brent Royal-Gordon

Je viens de passer quelques heures à suivre un EXC_BAD_ACCESS et à constater que NSZombies et d’autres env env ne semblaient rien me dire.

Pour moi, c’était une déclaration stupide de NSLog avec des spécificateurs de format, mais aucun argument n’était adopté.

NSLog(@"Some silly log message %@-%@");

Fixé par

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);
7
Scott Heaberlin

Ce n'est pas une réponse complète, mais une situation spécifique dans laquelle j'ai reçu ceci est lorsque j'essaie d'accéder à un objet qui est "mort" parce que j'ai essayé d'utiliser autorelease:

netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];

Ainsi, par exemple, je transmettais cet objet sous forme d'objet à 'notifier' (enregistré comme écoutant, observateur, quel que soit l'idiome que vous préfériez), mais il était déjà mort une fois la notification envoyée et je recevais le EXC_BAD_ACCESS. Le changer en [[MyNetObject alloc] init] et le relâcher plus tard, le cas échéant, a corrigé l'erreur.

Une autre raison pour laquelle cela peut arriver est par exemple si vous transmettez un objet et essayez de le stocker:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Plus tard, lorsque vous essayez d'accéder à myObjectDefinedInHeader, vous risquez d'avoir des problèmes. En utilisant:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

peut être ce dont vous avez besoin. Bien sûr, ce ne sont là que quelques exemples de ce que j’ai vécu et il ya d’autres raisons, mais elles peuvent s’avérer insaisissables, aussi je les mentionne. Bonne chance!

6
Rob

Les vidéos WWDC 2010 sont disponibles pour tous les participants du programme de développement Apple. Voici une excellente vidéo: "Session 311 - Analyse de mémoire avancée avec des instruments", qui présente quelques exemples d'utilisation de zombies dans des instruments et du débogage d'autres problèmes de mémoire.

Pour un lien vers la page de connexion, cliquez HERE .

6
Jonah

Juste pour ajouter une autre situation où cela peut se produire:

J'ai eu le code:

NSMutableString *string;
[string   appendWithFormat:@"foo"];

J'avais évidemment oublié d'allouer de la mémoire pour la chaîne:

NSMutableString *string = [[NSMutableString alloc] init];
[string   appendWithFormat:@"foo"];

résout le problème.

5
gnuchu

Je trouve utile de définir un point d'arrêt sur objc_exception_throw. De cette façon, le débogueur devrait se rompre lorsque vous obtenez EXC_BAD_ACCESS.

Les instructions peuvent être trouvées ici DebuggingTechniques

5
lyonanderson

Une autre méthode permettant de capturer les exceptions EXC_BAD_ACCESS avant qu’elles ne se produisent est le analyseur statique , dans XCode 4+.

Exécutez l'analyseur statique avec Produit> Analyser (shift + cmd + B). En cliquant sur les messages générés par l'analyseur, vous superposerez un diagramme sur votre source indiquant la séquence de conservation/libération de l'objet incriminé.

enter image description here

5
ericsoco

Utilisez la simple règle suivante: "si vous ne l'avez pas alloué ou conservé, ne le libérez pas".

4
Gamma-Point

Comment déboguer EXC_BAD_ACCESS

Consultez le lien ci-dessus et procédez comme il est indiqué .... Quelques instructions rapides pour utiliser NSZombies

Lancez l'application et après son échec (devrait afficher "Interrupted" plutôt que "EXC_BAD_ACCESS" ... vérifiez la console (Exécuter> Console) ... il devrait y avoir un message indiquant maintenant à quel objet il essayait d'accéder.

-Ben

4
Ben Call

J'ai rencontré EXC_BAD_ACCESS sur l'iPhone uniquement en essayant d'exécuter une méthode C incluant un grand tableau. Le simulateur a pu me donner assez de mémoire pour exécuter le code, mais pas l'appareil (le tableau comptait un million de caractères, donc c'était un peu excessif!).

EXC_BAD_ACCESS est apparu juste après le point d’entrée de la méthode et m'a laissé perplexe pendant un bon bout de temps car il était loin de la déclaration de tableau.

Peut-être que quelqu'un d'autre pourrait tirer profit de mes quelques heures de tirage de cheveux.

3
mblackwell8

J'ai oublié de me rendre moi-même dans une méthode init ...;)

3
denbec

C'est un excellent fil. Voici mon expérience: je me suis trompé avec le mot-clé Retenir/Attribuer dans une déclaration de propriété. J'ai dit:

@property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;

où j'aurais dû dire

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
3
fool4jesus

Comment je traite avec EXC_BAD_ACCESS

Parfois, j’ai l’impression que lorsqu’une erreur EXC_BAD_ACCESS est levée, xcode affichera l’erreur dans la classe main.m ne donnant aucune information supplémentaire sur l’endroit où le crash se produit (parfois).

À cette époque, nous pouvons définir un point d'arrêt exceptionnel dans Xcode pour que, lorsqu'une exception est interceptée, un point d'arrêt soit placé et informe directement l'utilisateur que le blocage s'est produit sur cette ligne.

enter image description here

3
iPrabu

Je débogue et remanie le code pour résoudre cette erreur au cours des quatre dernières heures. Un post ci-dessus m'a amené à voir le problème:

Propriété avant: startPoint = [[DataPoint alloc] init]; startPoint = [DataPointList objectAtIndex: 0];
. . . x = startPoint.x - 10; // EXC_BAD_ACCESS

Propriété après: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] keep];

Au revoir EXC_BAD_ACCESS

3
objC-InDC

J'ai oublié de retirer un pointeur non alloué de dealloc. Je recevais l'exc_bad_access sur mon rootView d'un UINavigationController, mais seulement de temps en temps. J'ai supposé que le problème venait de rootView car il plantait à mi-parcours de son viewDidAppear {}. Il s'est avéré que cela ne s'est produit qu'après que j'ai ouvert la vue avec la mauvaise version de dealloc {}, et c'était tout!

"EXC_BAD_ACCESS" [Passage au processus 330] Pas de mémoire disponible pour la programmation: mise en sécurité de l'appel de malloc

Je pensais que c'était un problème où j'essayais d'allouer ... pas où j'essayais de libérer un non-alloc, D'oh!

3
Josh

J'espère que vous libérez la 'chaîne' quand vous avez terminé!

3
shnaps

Je me rends compte que cela a été demandé il y a quelque temps, mais après avoir lu ce fil de discussion, j'ai trouvé la solution pour XCode 4.2: Produit -> Schéma d'édition -> onglet Diagnostics -> Activer les objets Zombie.

M'a aidé à trouver un message envoyé à un objet désalloué.

2
Sean Aitken

Lorsque vous avez une récursion infinie, je pense que vous pouvez également avoir cette erreur. C'était un cas pour moi.

2
coolcool1994

Je viens d'avoir ce problème. Pour moi, la raison était de supprimer un objet géré Core Data et d'essayer de le lire ensuite à partir d'un autre endroit.

2
konryd

Je débogue et remanie le code pour résoudre cette erreur au cours des quatre dernières heures. Un post ci-dessus m'a amené à voir le problème:

Propriété avant:

startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS

Propriété après:

startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];

Au revoir EXC_BAD_ACCESS

Merci beaucoup pour votre réponse. J'ai été aux prises avec ce problème toute la journée. Vous êtes génial!

2
victorsk

Juste pour ajouter

Lynda.com a un fantastique DVD appelé

formation essentielle sur le SDK pour iPhone

et Chapitre 6, Leçon 3: Tout sur EXEC_BAD_ACCESS et travailler avec des zombies.

C’était génial pour moi de comprendre non seulement le code d’erreur, mais aussi comment utiliser Zombies pour obtenir plus d’informations sur l’objet publié.

2
balexandre

Pour vérifier quelle peut être l'erreur

Utilisez NSZombieEnabled.

Pour activer la fonction NSZombieEnabled dans votre application:

Choisissez Projet> Modifier l’exécutable actif pour ouvrir la fenêtre Informations sur l’exécutable. Cliquez sur Arguments. Cliquez sur le bouton Ajouter (+) dans la section "Variables à définir dans l'environnement". Entrez NSZombieEnabled dans la colonne Nom et YES dans la colonne Valeur. Assurez-vous que la coche pour l'entrée NSZombieEnabled est sélectionnée.

J'ai trouvé cette réponse sur iPhoneSDK

2
zambono

Les appels NSAssert () pour valider les paramètres de la méthode sont assez pratiques pour localiser et éviter les nuls.

2
Ryan Townshend

Avant de faire quoi que ce soit, vous devriez essayer:

Produit -> Nettoyer

Et courir à nouveau. Cela a fonctionné pour moi. Sinon, j'aurais perdu des heures.

1
rghome

Je l'ai eu parce que je n'utilisais pas [self performSegueWithIdentifier:sender:] et -(void) prepareForSegue:(UIstoryboardSegue *) right

1
DHShah01

Encore une autre possibilité: en utilisant des blocs dans les files d'attente, il peut facilement arriver que vous essayiez d'accéder à un objet d'une autre file d'attente, qui a déjà été désalloué à ce moment-là. Généralement, lorsque vous essayez d'envoyer quelque chose à l'interface graphique. Si votre point d'arrêt d'exception est défini à un endroit étrange, cela peut en être la cause.

1
brainray

XCode 4 et supérieur, cela a été rendu très simple avec Instruments. Il suffit de lancer Zombies in Instruments. Ce tutoriel l'explique bien: débogage des erreurs d'erreur xcode exc_bad_access

1
Rons Micheal

N'oubliez pas le symbole @ lors de la création de chaînes, traiter C-strings comme NSStrings provoquera EXC_BAD_ACCESS.

Utilisez ceci:

@"Some String"

Plutôt que cela:

"Some String"

PS - généralement lors du remplissage du contenu d'un array avec beaucoup d'enregistrements.

1
Artur

Dans mon cas, cela a été causé par l'opération de suppression tableview. Cette solution a résolu mon exception d’accès interdit: https://stackoverflow.com/a/4186786/538408

0
Murat