Why is raising an NSException not bringing down my application?

后端 未结 6 728
难免孤独
难免孤独 2020-12-30 08:23

The Problem

I\'m writing a Cocoa application and I want to raise exceptions that will crash the application noisily.

I have the following li

6条回答
  •  情书的邮戳
    2020-12-30 09:24

    So it turns out the reason that it appears that the exception handler doesn't get called in your application delegate methods is that _NSAppleEventManagerGenericHandler (a private API) has a @try @catch block that is catching all exceptions and just calling NSLog on them before returning with a errAEEventNotHandled OSErr. This means that not only are you going to miss any exceptions in app start up, but essentially any exceptions that occur inside of handling an AppleEvent which includes (but is not limited to) opening documents, printing, quitting and any AppleScript.

    So, my "fix" for this:

    #import 
    #include 
    
    @interface NSAppleEventManager (GTMExceptionHandler)
    @end
    
    @implementation NSAppleEventManager (GTMExceptionHandler)
    + (void)load {
      // Magic Keyword for turning on crashes on Exceptions
      [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }];
    
      // Default AppleEventManager wraps all AppleEvent calls in a @try/@catch
      // block and just logs the exception. We replace the caller with a version
      // that calls through to the NSUncaughtExceptionHandler if set.
      NSAppleEventManager *mgr = [NSAppleEventManager sharedAppleEventManager];
      Class class = [mgr class];
      Method originalMethod = class_getInstanceMethod(class, @selector(dispatchRawAppleEvent:withRawReply:handlerRefCon:));
      Method swizzledMethod = class_getInstanceMethod(class, @selector(gtm_dispatchRawAppleEvent:withRawReply:handlerRefCon:));
      method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
    - (OSErr)gtm_dispatchRawAppleEvent:(const AppleEvent *)theAppleEvent
                          withRawReply:(AppleEvent *)theReply
                         handlerRefCon:(SRefCon)handlerRefCon {
      OSErr err;
      @try {
        err = [self gtm_dispatchRawAppleEvent:theAppleEvent withRawReply:theReply handlerRefCon:handlerRefCon];
      } @catch(NSException *exception) {
        NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();
        if (handler) {
          handler(exception);
        }
        @throw;
      }
      @catch(...) {
        @throw;
      }
      return err;
    }
    @end
    

    Fun extra note: NSLog(@"%@", exception) is equivalent to NSLog(@"%@", exception.reason). NSLog(@"%@", [exception debugDescription]) will give you the reason plus the fully symbolicated stack backtrace.

    The default version in the _NSAppleEventManagerGenericHandler just calls NSLog(@"%@", exception) (macOS 10.14.4 (18E226))

提交回复
热议问题