MonoTouch: uncaughtExceptionHandler?

2019-02-17 06:57发布

问题:

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:@" "];
    ....
}

回答1:

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.



回答2:

    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);
        ...
    }


回答3:

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);
  }
}