Xcode n'affiche pas la ligne qui provoque un plantage

126

Chaque fois que mon application plante, Xcode met en évidence l'appel UIApicationMain () dans la fonction main () comme la ligne qui a causé le crash. Dans certains cas, c'était normal (erreur de segmentation par exemple) mais le crash que j'essaie de gérer est un simple SIGABRT avec des informations détaillées enregistrées dans la console:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: Date)'

Xcode avait l'habitude d'afficher la ligne juste avec les anciens SDK, mais depuis la mise à niveau vers Xocde 4.2, cela a changé. Il est assez évident que Xcode sait exactement ce qui a causé le crash (ou pourrait le savoir), mais il ne montre toujours pas la ligne réelle. Existe-t-il un correctif ou une solution de contournement pour cela?

JonasG
la source
2
Compilez-vous pour Release? Si tel est le cas, essayez de définir le schéma sur Debug.
epatel
Il se peut aussi que certains xib soient défectueux, provoquant le crash du programme à un endroit en dehors de votre propre code source, donc ne montrant aucun fichier. L'erreur décrit un problème pour une clé de dictionnaire nommée "Date"
epatel
1
Apple devrait embaucher plus de testeurs;)
Amr Lotfy

Réponses:

301

Vous devez également vous assurer que vous avez défini des points d'arrêt pour toutes les exceptions. Cela entraînera l'arrêt de Xcode à la ligne où l'exception se produit. Procédez comme suit [dans Xcode 4]:

  1. Dans le navigateur de projet sur le côté gauche de Xcode, cliquez sur le navigateur de point d'arrêt (presque tout le chemin vers le côté droit de la barre de boutons supérieure. L'icône ressemble à une grosse flèche droite).

  2. Au bas du navigateur, cliquez sur le bouton "+".

  3. Cliquez sur "Ajouter un point d'arrêt d'exception".

  4. Un nouveau point d'arrêt sera créé. Il doit être configuré selon les besoins, mais vous pouvez modifier son comportement.

  5. Exécutez votre projet et reproduisez l'exception.

Vous avez également mentionné que vous vous êtes lié à des bibliothèques / frameworks tiers. Si l'exception se produit dans ces cadres, vous allez avoir du mal car le code est compilé et Xcode ne peut pas réellement vous montrer la ligne qui a causé l'exception. Si tel est le cas et que vous êtes certain que vous utilisez correctement les bibliothèques, vous devez alors déposer un rapport de bogue aux responsables de ces bibliothèques.

Charretier
la source
4
Je suis un noob et je me suis développé presque un mois sans ça ... ça change ma vie.
Jonny Burger
4
Mon ami s'est inscrit pour un compte SO juste pour voter pour ce message.
Alex Spencer du
1
cela s'appelle la moitié du cul sur une partie de pommes dans mon livre
ChuckKelly
1
Fait cela, mais ne trouve toujours pas où il a appelé length sur un nul :(
Shereef Marzouk
1
Cela fonctionne, mais l'inconvénient est qu'il ne produit plus les détails de l'exception dans la console de débogage. Je peux donc désactiver ce point d'arrêt et voir les détails et la trace de l'exception, mais pas où cela s'est produit, ou l'activer pour voir où cela s'est produit, mais pas POURQUOI. Quelqu'un sait comment avoir les deux?
Gabriel Jensen
27

Suivez simplement les instructions de cette réponse StackOverflow:

Activer les zombies

En gros, il vous suffit de "Activer les zombies". Ensuite, Xcode devrait se briser sur la ligne à l'origine du problème.

entrez la description de l'image ici

(Il est absolument choquant que, même en 2017, Xcode ait toujours ceci désactivé par défaut. Pourquoi ne voudriez-vous pas voir la ligne qui a causé le problème? Et " Activer les objets Zombie "?! Vraiment?! Les auteurs de Xcode vraiment pense que c'est un nom utile, qui aurait du sens pour les nouveaux développeurs? Il est déprimant de constater à quel point la note de Xcode est médiocre, année après année, dans l'App Store. Personne n'écoute ...)

Mike Gledhill
la source
6
Xcode est le pire environnement de programmation que j'ai utilisé jusqu'à présent.
Étudiant
Ce que je trouve intéressant (en tant que développeur Visual Studio), c'est le nombre de développeurs Xcode que j'ai rencontrés, qui insistent sur le fait que Xcode est le meilleur environnement qu'ils aient jamais utilisé. Logique, sympathique et serviable .. mais avec quelques bizarreries. Même maintenant, en novembre 2019, Xcode a une note App Store de 3,1, la plupart des gens lui attribuant 5 étoiles ou 1 étoile. Personne n'écoute ....
Mike Gledhill
9

Modifier le régime actuel et permettre NSZombieEnabled, MallocStackLogginget guard malloc. Ensuite, lorsque votre application plante, saisissez ceci dans la console gdb:

(gdb) info malloc-history 0x543216

Remplacez-la 0x543216par l'adresse de l'objet qui a causé le NSInvalidArgumentExceptionet cela devrait vous donner une trace de pile beaucoup plus utile, montrant les lignes de votre code qui causent le plantage.

chown
la source
1
J'ai essayé ceci et j'ai reçu l'erreur: «info» n'est pas une commande valide. Aucun conseil?
achi
@EliGregory assurez-vous que votre débogueur est défini sur gdb et non sur lldb par défaut. Vous pouvez le modifier dans le menu Edit Scheme sous la section run.
chown
2

J'ai vu ce comportement dans un code fortement optimisé; vérifier, ajuster le niveau d'optimisation de votre cible et ceux des bibliothèques tierces peuvent vous aider. (Réglage du niveau d'optimisation LLVM 3.0)

Générez-vous des symboles de débogage?

FluffulousChimp
la source
D'accord. Si vous essayez de déboguer, le niveau d'optimisation doit être défini sur 0 (aucune optimisation) dans vos paramètres de construction.
Carter
1

J'ai écrit du code pour générer un crash d'index hors des limites. Voici l'exception lancée.

2017-01-07 04:02:57.606 testABC[1694:52966] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010e85cd4b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010e2be21e objc_exception_throw + 48
    2   CoreFoundation                      0x000000010e8b5c2f -[__NSSingleObjectArrayI objectAtIndex:] + 111
    3   testABC                             0x000000010dce962d -[ViewController ComplexFunction] + 61
    4   testABC                             0x000000010dce95db -[ViewController thirdFunction] + 43
    5   testABC                             0x000000010dce959b -[ViewController secondFunction] + 43
    6   testABC                             0x000000010dce955b -[ViewController firstFinction] + 43
    7   testABC                             0x000000010dce96c2 -[ViewController viewDidAppear:] + 50
    8   UIKit                               0x000000010ee28a6c -[UIViewController _setViewAppearState:isAnimating:] + 945
    9   UIKit                               0x000000010ee2b7da __64-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:]_block_invoke + 42
    10  UIKit                               0x000000010ee29ac4 -[UIViewController _executeAfterAppearanceBlock] + 86
    11  UIKit                               0x000000010ec8d77c _runAfterCACommitDeferredBlocks + 653
    12  UIKit                               0x000000010ec7a273 _cleanUpAfterCAFlushAndRunDeferredBlocks + 566
    13  UIKit                               0x000000010ec9d757 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke_2 + 194
    14  CoreFoundation                      0x000000010e8016ac __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    15  CoreFoundation                      0x000000010e7e66f4 __CFRunLoopDoBlocks + 356
    16  CoreFoundation                      0x000000010e7e5e65 __CFRunLoopRun + 901
    17  CoreFoundation                      0x000000010e7e5884 CFRunLoopRunSpecific + 420
    18  GraphicsServices                    0x00000001126d9a6f GSEventRunModal + 161
    19  UIKit                               0x000000010ec80c68 UIApplicationMain + 159
    20  testABC                             0x000000010dce99df main + 111
    21  libdyld.dylib                       0x000000011174968d start + 1
    22  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Si vous lisez attentivement le First Throw call stack

0   CoreFoundation              0x000000010e85cd4b __exceptionPreprocess + 171
1   libobjc.A.dylib             0x000000010e2be21e objc_exception_throw + 48

0 and 1 sont les processus système après un crash.

 2   CoreFoundation             0x000000010e8b5c2f -[__NSSingleObjectArrayI objectAtIndex:] + 111

2 est la ligne qui a causé l'exception.

3   testABC                     0x000000010dce962d -[ViewController ComplexFunction] + 61

3vous indique que le nom de classe ( ViewController) et la fonction naem ( ComplexFunction) dans lesquels l'exception a été lancée.

AsifHabib
la source
4
Euh, d'accord. Vous avez tout à fait raison, mais est-ce amical? Dans tout environnement de développement moderne (à partir des années 1990), lorsqu'une exception se produit, vous êtes dirigé vers la ligne qui a causé le problème. Alors que Xcode ... eh bien ... vous donne une trace de pile comme celle-ci. Même Turbo Pascal n'était pas si démodé !!!
Mike Gledhill
4
Il est ridicule que la société qui est censée être connue pour la "meilleure expérience utilisateur" ne se rende pas compte que tous les développeurs des 20 dernières années sont habitués à voir le numéro de ligne où une exception est lancée et PAS EN ASSEMBLAGE. Est-ce que je deviens fou? Chaque langue avec laquelle j'ai travaillé toute ma vie donne des numéros de ligne. Même C ou C ++.
mylovemhz