7

In MonoTouch, how do I register an uncaught exception handler (or similar function)

In Obj-C:

void uncaughtExceptionHandler(NSException *exception) {
      [FlurryAnalytics logError:@"Uncaught" message:@"Crash!" exception:exception];
  }

- (void)applicationDidFinishLaunching:(UIApplication *)application { 
     NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
     [FlurryAnalytics startSession:@" "];
    ....
}
Rolf Bjarne Kvinge
  • 19,253
  • 2
  • 42
  • 86
Ian Vink
  • 66,960
  • 104
  • 341
  • 555

3 Answers3

3
    public delegate void NSUncaughtExceptionHandler(IntPtr exception);

    [DllImport("/System/Library/Frameworks/Foundation.framework/Foundation")]
    private static extern void NSSetUncaughtExceptionHandler(IntPtr handler);

    // This is the main entry point of the application.
    private static void Main(string[] args)
    {
            NSSetUncaughtExceptionHandler(
                Marshal.GetFunctionPointerForDelegate(new NSUncaughtExceptionHandler(MyUncaughtExceptionHandler)));

            ...
    }

    [MonoPInvokeCallback(typeof(NSUncaughtExceptionHandler))]
    private static void MyUncaughtExceptionHandler(IntPtr exception)
    {
        var e = new NSException(exception);
        ...
    }
Alex
  • 172
  • 1
  • 6
  • Awesome, thank you! Only thing is the constructor for NSException that takes an IntPtr is protected, so you need to subtype it and expose that version of the constructor. Otherwise this was super-helpful. – Lee Richardson May 06 '16 at 17:30
  • [Here](http://stackoverflow.com/questions/37525472/create-nsexception-from-intptr/37527174#37527174) you can see how `NSException` accepts an `IntPtr` as argument. – testing May 31 '16 at 12:08
0

This does the job. Call the SetupExceptionHandling() method on app launch. The magic is the NSRunLoop part. But the app is going to be in a weird state at that point, with unpredictable effects. Therefore, I would strongly suggest killing the app after the user decides what to do with the exception -- for example, by re-throwing it.

public static class IOSStartupTasks {
  private static bool _HaveHandledException;
  public static void HandleException(object sender, UnhandledExceptionEventArgs e) {
    if (!(_HaveHandledException)) {
      _HaveHandledException = true;
      UIAlertView alert = new UIAlertView("Error", "Bad news", "report", "just crash");
      alert.Delegate = whatever; // delegate object should take the exception as an argument and rethrow when it's done handling user input.
      alert.Show();
      NSRunLoop.Current.RunUntil(NSDate.DistantFuture); // keeps the app alive, but likely with weird effects, so make sure you don't let the user back into the main app.
    }
  }

  public static void SetupExceptionHandling() {
    AppDomain domain = AppDomain.CurrentDomain;
    domain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => 
      IOSStartupTasks.HandleException(sender, e);
  }
}
William Jockusch
  • 26,513
  • 49
  • 182
  • 323
-4

You add a try-catch handler around the code that (might) throw NSExceptions:

try {
    FlurryAnalytics.StartSession (" ");
} catch (MonoTouchException ex) {
    Console.WriteLine ("Could not start flurry analytics: {0}", ex.Message);
}

MonoTouch already installs an uncaught exception handler, and automatically translates those ObjectiveC exceptions to managed exceptions.

Rolf Bjarne Kvinge
  • 19,253
  • 2
  • 42
  • 86