如何阻止HIToolbox捕获我的异常?

Joh*_*her 4 cocoa exception-handling macos-carbon objective-c

这个问题来自于我的另一个问题,即为什么我的应用程序没有被例外打倒.

问题

当通过Action在主线程上抛出异常时,应用程序仍然不会崩溃.

根据Dave对原始问题的回答,我在NSApplication上实现了reportException类,并设置了未捕获的异常处理程序.

我在我的app委托中有以下内容,我已经连接到我的UI中的一个按钮进行测试.

-(IBAction)crashOnMainThread:(id)sender {
    [self performSelectorOnMainThread:@selector(crash) withObject:nil waitUntilDone:YES];
}

-(void)crash {
    // To test out the exception handling
    [NSException raise:NSInternalInconsistencyException format:@"This should crash the app."];
}
Run Code Online (Sandbox Code Playgroud)

当我按下按钮时,我的应用程序不会崩溃.当我查看控制台日志时,我看到了:

06/09/2010 14:12:25 EHTest1[26384]  HIToolbox: ignoring exception 'This should crash the app.' that raised inside Carbon event dispatch
(
    0   CoreFoundation                      0x00007fff80ab4cc4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x00007fff819560f3 objc_exception_throw + 45
    2   CoreFoundation                      0x00007fff80ab4ae7 +[NSException raise:format:arguments:] + 103
    3   CoreFoundation                      0x00007fff80ab4a74 +[NSException raise:format:] + 148
    4   EHTest1                             0x00000001000010e3 -[EHTest1_AppDelegate crashLapsus] + 63
    5   Foundation                          0x00007fff88957c25 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] + 234
    6   Foundation                          0x00007fff8896ad48 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:] + 143
    7   EHTest1                             0x0000000100001030 -[EHTest1_AppDelegate crashOnMainThread:] + 60
    8   AppKit                              0x00007fff85c7e152 -[NSApplication sendAction:to:from:] + 95
    9   AppKit                              0x00007fff85ca26be -[NSMenuItem _corePerformAction] + 365

    ** Snip **
Run Code Online (Sandbox Code Playgroud)

看起来Carbon正在捕捉异常,这真的很烦人.

这表明对于任何操作代码,您需要立即在后台线程中运行它,以便将任何异常注册为未捕获.咦?我没见过任何像这样的结构代码.

我试过的

延迟崩溃应用程序,因此它没有连接到UI元素.它崩溃了.

我已尝试在我的应用委托中使用此安装自定义NSExceptionHandler:

-(BOOL)exceptionHandler:(NSExceptionHandler *)sender 
  shouldHandleException:(NSException *)exception 
                   mask:(unsigned int)aMask {
      abort();
      return YES;
}

-(void)applicationWillFinishLaunching:(NSNotification *)aNotification {
      NSExceptionHandler *handler = [NSExceptionHandler defaultExceptionHandler];
      [handler setExceptionHandlingMask:NSLogAndHandleEveryExceptionMask];
      [handler setDelegate:self];
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是每次异常都会崩溃,无论是否被捕获.

如果我尝试检查掩码并且没有在捕获的异常上崩溃,我回到方块1,因为看起来HIToolbox以与try/catch块完全相同的方式捕获异常.

问题

  • 如何阻止HIToolbox捕获异常,以便我的应用程序使用未捕获的异常处理程序并崩溃?
  • 可以运行与操作在同一个调用堆栈中的代码吗?当然这没关系?
  • 如果不行,有什么替代方案?

这让我起了墙,所以任何帮助都会非常感激.

Dav*_*her 6

我回答关于这个问题你的最后一个问题,跑与碳的捕获使HIToolbox通过IBActions抛出异常的同样的问题.

首先,撤消我之前回答中提到的所有内容.由于某种原因,它不适用于IBActions.我的直觉是,使HIToolbox生活在异常处理链的低级,并得到任何IBAction为/ GUI例外的NSApplication有机会了.你可以注册任何自定义的异常处理函数NSSetUncaughtExceptionHandler()的生活(我相信)在链的顶端.

你在NSExceptionHandling的正确轨道上:

  1. ExceptionHandling.framework添加到Xcode项目中
  2. #import "ExceptionHandlerDelegate.h" 到您的AppDelegate.m(或自定义Singleton异常类)

AppDelegate.m中:

// Very first message sent to class
+ (void)initialize
{
    NSExceptionHandler *exceptionHandler = [NSExceptionHandler defaultExceptionHandler];
    unsigned int handlingMask = NSLogAndHandleEveryExceptionMask;
    [exceptionHandler setExceptionHandlingMask:handlingMask];
    [exceptionHandler setDelegate:self];

    // ...
}


#pragma mark -
#pragma mark NSExceptionHandler Delegate Methods

// Called 1st: Should NSExceptionHandler log the exception?
- (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldLogException:(NSException *)exception mask:(unsigned int)aMask
{
    // ...log NSException if desired...

    return NO;  // Changes to YES if NSExceptionHandler should handle logging
}

// Called 2nd: Should NSExceptionHandler handle the exception?
- (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldHandleException:(NSException *)exception mask:(unsigned int)aMask
{
    // ...crash your app here (e.g. [NSApp terminate:self]; )

    // ...or handle the NSException and return YES/NO accordingly

    return NO;  // If app crashed, never gets returned - should crash before that
}
Run Code Online (Sandbox Code Playgroud)

NSLogAndHandleEveryExceptionMask标志告诉NSExceptionHandler捕捉每一个异常也可以(为您的应用程序而已,我相信),无论在哪里上存在异常链.

这意味着,@捕捉/ @尽量/ @终于块将无法工作,因为NSHandleOtherExceptionMask标志告诉NSExceptionHandler捕获到异常处理程序链"一切都在它下面." 您可以删除标志,但随后HIToolKit可能会再次得到任何IBAction为例外,因为它似乎在说链要低一些.

Apple的文档有关于标志的信息: NSExceptionHandler docs

因此,当引发NSException时(在应用程序AFAIK中的任何位置),并且设置了NSLogAndHandleEveryExceptionMask,这些在委托中按顺序调用:

  1. -exceptionHandler:shouldLogException:mask: 被称为第一.
  2. -exceptionHandler:shouldHandleException:mask: 被称为第二.

只需将您的"崩溃代码"放在第二个委托方法中,您就可以了.


有用的文章:了解Cocoa中的异常和处理程序


我认为你无法让NSExceptionHandler的委托工作的原因是因为它与自定义方法集不兼容NSSetUncaughtExceptionHandler(),这是我在上一个问题中的答案的一部分.每个Apple:

NSExceptionHandler类提供用于监视和调试Objective-C程序中的异常条件的工具.它的工作原理是通过NSSetUncaughtExceptionHandler函数安装一个特殊的未捕获异常处理程序.因此,要使用NSExceptionHandler的服务,您不能安装自己的自定义未捕获异常处理程序.

当您覆盖NSApplication的-reportException:方法时,它也可能无法正常工作.

最后,似乎没有必要使用@ catch/@ try/@ finally(也是我以前的答案的一部分).内部配置NSExceptionHandler +initialize似乎立即"启动",与重写NSApplication的-reportException:方法不同.