这个问题来自我关于why my app isn't being brought down by exceptions的另一个问题。
问题
当通过Action在主线程上抛出异常时,应用程序仍然不会崩溃。
根据Dave's answer to my original question,我在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."];
}
当我按下按钮时,我的应用程序不会崩溃。当我查看控制台日志时,我看到了:
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元素。它崩溃了。
我已尝试在我的应用委托中使用此安装自定义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];
}
这里的问题是每次异常都会崩溃,无论是否被捕获。
如果我尝试检查掩码并且没有在捕获的异常上崩溃,我回到方块1,因为看起来HIToolbox以与try / catch块完全相同的方式捕获异常。
问题
这让我起了墙,所以任何帮助都会非常感激。
我回答了关于这个问题的最后一个问题,并且遇到了与Carbon的HIToolbox相同的问题,捕获了IBActions抛出的异常。
首先,撤消我在previous answer中提到的所有内容。由于某种原因,它不适用于IBActions。我的预感是HIToolbox在异常处理链上的寿命较低,并且在NSApplication有机会之前获得任何IBAction / GUI异常。您可以在NSSetUncaughtExceptionHandler()
注册的任何自定义异常处理函数(我相信)都位于链的顶部。
你在NSExceptionHandling的正确轨道上:
#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块将无效,因为NSHandleOtherExceptionMask
标志告诉NSExceptionHandler在异常处理程序链上捕获“它下面的所有内容”。您可以删除该标志,但随后HIToolKit可能会再次获得任何IBAction异常,因为它在所述链上看起来较低。
Apple的文档有关于旗帜的信息:NSExceptionHandler docs
因此,当引发NSException时(在应用程序AFAIK中的任何位置),并且设置了NSLogAndHandleEveryExceptionMask,这些在委托中按顺序调用:
-exceptionHandler:shouldLogException:mask:
被称为第一。-exceptionHandler:shouldHandleException:mask:
被称为第二名。只需将您的“崩溃代码”放在第二个委托方法中,您就可以了。
有用的文章:Understanding Exceptions and Handlers in Cocoa
我认为你无法使NSExceptionHandler的委托工作的原因是因为它与使用NSSetUncaughtExceptionHandler()
的自定义方法集不兼容,这是我之前的问题中答案的一部分。每Apple:
NSExceptionHandler类提供用于监视和调试Objective-C程序中的异常条件的工具。它的工作原理是通过NSSetUncaughtExceptionHandler函数安装一个特殊的未捕获异常处理程序。因此,要使用NSExceptionHandler的服务,您不能安装自己的自定义未捕获异常处理程序。
当您覆盖NSApplication的-reportException:
方法时,它也可能无法正常工作。
最后,似乎没有必要使用@ catch / @ try / @ finally(也是我以前的答案的一部分)。与重写NSApplication的+initialize
方法不同,在-reportException:
中配置NSExceptionHandler似乎立即“启动”。
你不能可靠。除非明确记录,否则不支持跨API边界抛出异常(我无法想到任何明确记录的情况)。