62 votes

Comment implémentez-vous la gestion globale des exceptions iPhone?

J'ai un crash dans mon application iPhone qui jette une exception NSException. Les rapports d'incident sont complètement ambigus quant à l'emplacement de l'erreur et à sa cause. Existe-t-il un moyen intelligent pour moi de définir un gestionnaire d'exception de premier niveau quelque part pour voir ce qui le cause? Je ne peux pas reproduire le problème moi-même, mais quelques-uns de mes utilisateurs bêta le peuvent certainement.

Quelle est une façon intelligente de gérer un problème de cette nature?

85voto

Paul McCabe Points 1253

Il semble que vous vous poser deux questions: comment définir un niveau supérieur gestionnaire d'exception; et la façon de traiter la question de la détermination de ce que la cause est.

La capture de l'exception qui peut être fait de plusieurs façons différentes, mais pour cela, la meilleure approche semble être de définir un gestionnaire d'exception à l'aide de NSSetUncaughtExceptionHandler.

Lorsqu'une exception est déclenchée dans votre application, il est géré par un gestionnaire d'exceptions par défaut. Ce gestionnaire ne fait rien de plus que l'enregistrement d'un message à la console avant l'application se ferme. Vous pouvez contourner ce problème en définissant vous propre gestionnaire d'exception à l'aide de la fonction indiquée ci-dessus. Le meilleur endroit pour le faire, ce serait dans l'app délégué applicationDidFinishLaunching: la méthode.

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    NSSetUncaughtExceptionHandler(&myExceptionHandler);
}

Une fois que vous avez défini un gestionnaire personnalisé, vous aurez envie de développer sur la sortie par défaut pour vous aider à déterminer quelle est la cause.

void myExceptionHandler(NSException *exception)
{
    NSArray *stack = [exception callStackReturnAddresses];
    NSLog(@"Stack trace: %@", stack);
}

Malheureusement, par rapport à OSX iPhone semble assez limitée en ce qui concerne la production d'une belle trace de la pile. Le code ci-dessus va produire certains apparemment indésirable de sortie; toutefois, vous pouvez exécuter cette sortie dans les atos de l'outil, et vous devriez être en mesure de générer un utile trace de la pile.

Une autre option est de suivre les instructions sur http://rel.me/2008/12/30/getting-a-useful-stack-trace-from-nsexception-callstackreturnaddresses/ (lien mort) , qui aidera à produire une belle trace de la pile automatiquement.

Que cela va à des beta-testeurs, vous pouvez avoir à bricoler sur le point de le faire fonctionner pour vous.

Vous dites que vous n'avez pas été en mesure de reproduire le problème vous-même, seulement à vos utilisateurs. Dans ce cas, vous pourriez trouver cette note technique d'Apple utiles:

http://developer.apple.com/iphone/library/technotes/tn2008/tn2151.html

Mise à JOUR: même si ce post contient toujours des infos utiles, certains des liens qu'il contient sont morts irrevertably. Il est conseillé d'utiliser l'info de cette alternative post.

12voto

HDA Points 2590

Si vous envisagez de le faire sur votre propre vous pouvez utiliser l'une de ces approches

Approach1:

void onUncaughtException(NSException* exception)
{
//save exception details
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSSetUncaughtExceptionHandler(&onUncaughtException);
  //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
//Rest of the coding
}

Bookshare 2:

void onUncaughtException(NSException* exception)
{

//Save exception details

}

int main(int argc, char *argv[])
{
    @autoreleasepool {

        NSSetUncaughtExceptionHandler(&onUncaughtException);

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([SGGI_AppDelegate class]));
    }
}



-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
      //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
    //Rest of the coding
 }

Approcach3:

int main(int argc, char *argv[])
{
    @autoreleasepool {

        @try {

            return UIApplicationMain(argc, argv, nil, NSStringFromClass([SGGI_AppDelegate class]));
        }
        @catch (NSException *exception) {      
        //Save the exception
        }
        @finally {
        }

    }
}

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
      //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
    //Rest of the coding
 }

Note:

  • De mon point de vue, n'essayez pas d'envoyer les détails de l'exception au serveur au moment de l'envoyer s'écraser quand il commence de nouveau l'application.

  • Si vous allez utiliser NSUserDefaults pour enregistrer les détails de l'exception, alors vous devez le synchroniser au moment de s'écraser, sinon ça ne pas persister.

L'extrait de code suivant fait le travail.

   - (void)applicationWillTerminate:(UIApplication *)application
   {
       [[NSUserDefaults standardUserDefaults]synchronize];
   }
  • Si vous préférez enregistrer sur sqlite db puis il persiste même pas besoin de demander quelque chose à persister au moment de s'écraser

5voto

En XCode, vous devez toujours définir un point d'arrêt global pour objc_exception_throw . Ensuite, vous obtenez (généralement) une trace de pile beaucoup plus significative sur ce qui essaie réellement de lancer une exception.

Vous pouvez toujours obtenir des exceptions qui proviennent du code du minuteur ou d’autres emplacements sans votre propre code n’importe où dans la trace, mais si vous regardez la chaîne de méthodes, vous pouvez généralement comprendre en quoi consiste l’exception (comme si une notification était envoyée où la cible est parti).

3voto

Tina Points 31

BugSense .com est également disponible et gratuit pour les projets iOS

3voto

Matthew Frederick Points 14932

Une autre option pour le suivi des rapports d'incident est Plausible CrashReporter, le code open source pour vous envoyer automatiquement des rapports d'erreur à partir du champ.

Il y a aussi le CrashReporterDemo, une autre option open source qui est une combinaison de Plausible CrashReporter et un serveur de code afin de mieux suivre les rapports de plantage.

Et enfin, il y a MacDevCrashReporter, un service qui semble avoir des similitudes iOSExceptional.com, a suggéré dans une autre réponse. Je n'ai aucune idée de ce que leurs modalités de service sont, comme je n'ai pas signé pour la bêta. Certainement la peine de vérifier avant d'entrer trop profondément.

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