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

标签 objective-c cocoa exception-handling macos-carbon

这个问题是我在 why my app isn't being brought down by exceptions 上提出的另一个问题的后续问题.

问题

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

根据 Dave's answer to my original question ,我在 NSApplication 上实现了 reportException 类别并设置了未捕获的异常处理程序。

代码

我的应用委托(delegate)中有以下内容,我已将其连接到我的 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."];
}

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

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 **

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

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

我尝试过的

延迟使应用程序崩溃,使其不连接到 UI 元素。它崩溃了。

我尝试在我的应用程序委托(delegate)中使用它安装自定义 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];
}

这里的问题是它会在每次异常时崩溃,无论它是否被捕获。

如果我尝试检查掩码并且没有在捕捉到异常时崩溃,我回到方 block 1,因为 HIToolbox 捕捉异常的方式似乎与 try/catch block 完全相同。

问题

  • 如何阻止 HIToolbox 捕获异常,以便我的应用程序使用未捕获的异常处理程序并崩溃?
  • 运行与 Action 位于同一调用堆栈中的代码是否可以?这当然可以吗?
  • 如果不行,还有什么选择?

这让我难以自拔,非常感谢任何帮助。

最佳答案

我回答了你关于这个主题的最后一个问题,并遇到了与 Carbon 的 HIToolbox 捕获 IBActions 抛出的异常相同的问题。

首先,撤消我在 previous answer 中提到的所有内容.由于某种原因,它不适用于 IBActions。我的预感是 HIToolbox 位于异常处理链的较低位置,并在 NSApplication 有机会之前获取任何 IBAction/GUI 异常。您可以使用 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
}

NSLogAndHandleEveryExceptionMask 标志告诉 NSExceptionHandler 捕获它可以捕获的每个异常(我相信仅适用于您的应用程序),无论它存在于异常链的哪个位置。

这意味着 @catch/@try/@finally block 将不起作用,因为 NSHandleOtherExceptionMask 标志告诉 NSExceptionHandler 在异常中捕获“它下面的所有内容” -处理程序链。您可以删除该标志,但随后 HIToolKit 可能会再次获得任何 IBAction 异常,因为它似乎位于所述链的较低位置。

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

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

  1. -exceptionHandler:shouldLogException:mask: 首先被调用。
  2. -exceptionHandler:shouldHandleException:mask: 第二个调用。

只需将您的“崩溃代码”放入第二个委托(delegate)方法中,您应该没问题。


有用的文章:Understanding Exceptions and Handlers in Cocoa


我认为您无法让 NSExceptionHandler 的委托(delegate)工作的原因是因为它与使用 NSSetUncaughtExceptionHandler() 设置的自定义方法不兼容,这是我上一个问题的部分答案。每Apple :

The NSExceptionHandler class provides facilities for monitoring and debugging exceptional conditions in Objective-C programs. It works by installing a special uncaught exception handler via the NSSetUncaughtExceptionHandler function. Consequently, to use the services of NSExceptionHandler, you must not install your own custom uncaught exception handler.

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

最后,似乎没有必要使用@catch/@try/@finally(也是我之前回答的一部分)。在 +initialize 中配置 NSExceptionHandler 似乎会立即“启动”,这与重写 NSApplication 的 -reportException: 方法不同。

关于objective-c - 如何阻止 HIToolbox 捕获我的异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3652412/

相关文章:

macos - 错误: unlockFocus called too many time

objective-c - 如何在WebView中显示NSString内容(Cocoa Mac应用程序)

c - 我们如何像其他语言(C++ 和 Java)一样处理 C 中的错误和异常?

css - Objective-C 为 UiImageView 应用 css 样式

ios - mainBundle 上的 appStoreReceiptURL 总是返回 nil

objective-c - 确定给定日期的小时数(加上或减去 DST 轮类小时数)

C# - 如何处理/捕获 StackOverFlowExceptions?

rest - CakePHP 3.x REST API-调试关闭时的自定义错误消息

ios - 删除 bridgeToObjective-C 意味着我不能使用 NSRange

ios - 如何缓存 NSUrlSession 响应数据