如何实现全局 iPhone 异常处理?

问题描述 投票:0回答:6

我的 iPhone 应用程序发生了一次崩溃,确实抛出了 NSException。崩溃报告对于错误所在以及到底是什么导致了错误完全不明确。有没有一种聪明的方法可以让我在某处设置顶级异常处理程序来查看导致它的原因?我自己无法复制这个问题,但我的一些测试版用户当然可以。

处理这种性质的问题的明智方法是什么?

iphone objective-c cocoa-touch debugging exception
6个回答
85
投票

您似乎在这里问两个问题:如何设置顶级异常处理程序;以及如何处理确定根本原因的问题。

捕获异常可以通过几种不同的方式来完成,但对此最好的方法似乎是使用 NSSetUncaughtExceptionHandler 设置异常处理程序。

当您的应用程序中引发异常时,将由默认异常处理程序进行处理。该处理程序只是在应用程序关闭之前将消息记录到控制台。您可以通过使用上述函数设置您自己的自定义异常处理程序来覆盖它。执行此操作的最佳位置是在应用程序委托 applicationDidFinishLaunching: 方法中。

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

设置自定义处理程序后,您将需要扩展默认输出以帮助您确定原因。

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

不幸的是,与 OSX 相比,iPhone 在生成良好的堆栈跟踪方面显得相当有限。上面的代码会产生一些看似垃圾的输出;但是,您可以通过 atos 工具运行此输出,并且您应该能够从中生成有用的堆栈跟踪。

另一种选择是按照本文上的说明进行操作,这将有助于自动生成良好的堆栈跟踪。

由于此内容将提供给 Beta 测试人员,因此您可能需要进行修改才能使其为您工作。

您说您自己无法复制问题,只能复制您的用户。在这种情况下,您可能会发现 Apple 的此技术说明很有用:

https://developer.apple.com/library/content/technotes/tn2151/_index.html

更新:虽然这篇文章仍然包含有用的信息,但它包含的一些链接已经不可逆转地失效了。建议使用this替代帖子中的信息。


12
投票

如果您打算自己做,您可以使用以下方法之一

方法1:

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
}

方法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
 }

方法3:

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
 }

注:

  • 在我看来,不要尝试将异常详细信息发送到服务器 当他再次启动应用程序时崩溃时发送它。

  • 如果您要使用 NSUserDefaults 来保存异常详细信息,那么您必须在崩溃时同步它,否则它将不会持久。

以下代码片段可以完成这项工作。

   - (void)applicationWillTerminate:(UIApplication *)application
   {
       [[NSUserDefaults standardUserDefaults]synchronize];
   }
  • 如果您更喜欢将其保存在 sqlite 数据库上,那么它会自行持续存在,无需在崩溃时调用任何内容来持续存在

5
投票

在 XCode 中,您应该始终为

objc_exception_throw
设置全局断点。然后,您(通常)会获得更有意义的堆栈跟踪,了解实际试图抛出异常的内容。

您仍然可以获得源自计时器代码或其他位置的异常,而在跟踪中的任何位置都没有您自己的代码,但是如果您查看方法链,您通常可以大致了解异常的内容(例如在目标消失了)。


3
投票

跟踪崩溃报告的另一个选项是 Plausible CrashReporter,开源代码可自动从现场向您发送崩溃报告。

还有 CrashReporterDemo,这是另一个开源选项,它是 Plausible CrashReporter 和一些服务器代码的组合,可以更好地跟踪崩溃报告。

最后,还有 MacDevCrashReporter,这项服务似乎与 iOSExceptional.com 相似,在另一个答案中建议。我不知道他们的服务条款是什么,因为我还没有注册测试版。在深入之前绝对值得检查一下。


2
投票

你尝试过吗

NSSetUncaughtExceptionHandler


2
投票

查看批评主义。它超出了您在这里所要求的范围,因为它可以让您获取使用您的应用程序的所有用户的此信息,因此您应该能够看到自己的崩溃。

您还可以上传您的特定版本的 DYSM,它会自动在他们的网站上为您表示崩溃。这应该为您提供最清晰的堆栈跟踪,而无需连接到调试器。

您可能还想确保您已设置为在 Objetive-C 异常时中断。在 Xcode 4 中,在断点选项卡中,您可以添加在 C++ 和 Obj-C 异常上中断的断点异常。如果不启用此功能,大多数抛出异常的堆栈跟踪都毫无帮助。

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.