How do you implement global iPhone Exception Handling?

It seems like you are asking two questions here: how to set a top level exception handler; and how to deal with the issue of determining what the root cause is.

Catching the exception can be done in a few different ways, but for this the best approach would appear to be to set an exception handler using NSSetUncaughtExceptionHandler.

When an exception is raised in your app, it is handled by a default exception handler. This handler does nothing more than log a message to the console before the app closes. You can over-ride this by setting you own custom exception handler using the function stated above. The best place to do this would be in the app delegate applicationDidFinishLaunching: method.

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

Once you've set a custom handler, you'll want to expand on the default output in helping you determine what the cause is.

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

Unfortunately compared to OSX the iPhone appears quite limited in respect to producing a nice stack trace. The code above will produce some seemingly junk output; however, you can run this output through the atos tool, and you should be able to generate a useful stack trace from it.

Another option is to follow the instructions on this article which will help to produce a nice stack trace automatically.

As this is going out to beta testers you may have to tinker about to get it working for you.

You say that you've not been able to replicate the problem yourself, only your users. In this case you may find this technical note from Apple useful:

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

UPDATE: While this post still contains useful info, some of the links it contains are dead irrevertably. It is advised to use the info from this alternative post.

share edit
 
 
Google Toolbox for Mac's GTMStackTrace is a big help sometimes :) –  rpetrich  Aug 16 '09 at 5:22
2 
Why iterate through the stack yourself, when you can do NSLog(@"%@" stack) ? –  AlBlue  Aug 16 '09 at 11:22
 
Why not indeed. Edited, and thanks for the input. –  Paul McCabe  Aug 16 '09 at 12:02
 
Based on the lack of feedback I assume that this is still a problem. I've added a reference to Apple technical notes that may help. –  Paul McCabe  Aug 28 '09 at 13:21
 
How many cycles does myExceptionHandler have to run? I'm trying to show a UIAlertView but the app completely dies before it shows up. Can you force myExceptionHandler to hog more cycles? –  Mark  Dec 3 '10 at 1:36

If you are planning to do it on your own you could use one of these approaches

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
}

Approach2:

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:

  • In my perspective don't try to send the exception details to server at the time of crashing send it when he starts the app again.

  • If you are going to use NSUserDefaults to save exception details then you have to synchronise it at the time of crashing otherwise it won't persist.

The following code snippet does the job.

   - (void)applicationWillTerminate:(UIApplication *)application
   {
       [[NSUserDefaults standardUserDefaults]synchronize];
   }
  • If you prefer to save it on sqlite db then it persists itself no need to call anything to persist at the time of crashing
share edit
 
 
Has this worked for anyone? Cuz did not work for me :( I tried saving the nsarray obj / callStackSymbols in NSUserDefaults onUncaughtException method. In the next didFinishLaunchingWithOptions I was unable to get any object for the key which I used to save in NSUserDefaults. –  Abhijit  Feb 21 at 16:30 
 
@Abhijit - Synchronize ([[NSUserDefaults standardUserDefaults]synchronize])it after saving –  Durai Amuthan.H  Feb 22 at 6:27
 
:D All though I forgot to mention this but of course I remember synchronizing Userdefaults –  Abhijit  Mar 1 at 5:48
1 
Exactly what I needed to see. Excellent, Durai. –  Alex Zavatone  Dec 8 at 0:24

In XCode, you should always set a global breakpoint for objc_exception_throw. Then you (usually) get a far more meaningful stack trace as to what is actually trying to throw an exception.

You can still get exceptions that originate in timer code or other places without your own code anywhere in the trace, but if you look at the method chain you can usually figure out generally what the exception is about (like having a notification sent where the target is gone).

share edit
 
 
Is this only useful when using Xcode to run the app? Not on a production app (e.g., to write exceptions to a log file). –  Chris Prince  Mar 3 '14 at 22:41
 
Yes, only useful when XCode is running the app. –  Kendall Helmstetter Gelner  Mar 5 '14 at 11:51

Also BugSense.com is available and free for iOS projects

share edit
 
 
It's free for 30 days, right? –  abalogh  May 17 '11 at 12:28

Another option for tracking crash reports is Plausible CrashReporter, open source code to automatically send you crash reports from the field.

There's also the CrashReporterDemo, another open source option that is a combination of Plausible CrashReporter and some server code to better track crash reports.

And lastly, there's MacDevCrashReporter, a service that appears to have similarities to iOSExceptional.com, suggested in another answer. I have no idea what their terms of service are, as I've not signed up for the beta. Definitely worth checking before getting in too deeply.

share edit
 

Check out Crittercism. It goes above and beyond what you're asking of here in that it lets you get this information for all users using your app, so you should be able to see your own crash.

You can also upload the DYSM for your particular build and it will automatically symbolicate the crash for you on their website. That should provide you with the clearest stack-trace without being hooked up to the debugger.

You might also want to make sure you are set to break on Objetive-C exceptions. In Xcode 4, in the breakpoints tab, you can add a Breakpoint Exception that breaks on both/either C++ and Obj-C exceptions. Without this on, most stack traces for exceptions thrown are pretty unhelpful.

Good luck!

share edit
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值