Joh*_*her 10 crash cocoa multithreading exception raise
问题
我正在编写一个Cocoa应用程序,我想提出异常会使应用程序崩溃.
我的应用程序委托中有以下行:
[NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
abort();
Run Code Online (Sandbox Code Playgroud)
问题是,他们没有关闭应用程序 - 消息只是记录到控制台,应用程序继续它的快乐方式.
据我了解,例外的全部内容是它们在特殊情况下被解雇.在这种情况下,我希望应用程序以明显的方式退出.这不会发生.
我试过的
我试过了:
-(void)applicationDidFinishLaunching:(NSNotification *)note
// ...
[self performSelectorOnMainThread:@selector(crash) withObject:nil waitUntilDone:YES];
}
-(void)crash {
[NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
abort();
}
Run Code Online (Sandbox Code Playgroud)
哪个不起作用
-(void)applicationDidFinishLaunching:(NSNotification *)note
// ...
[self performSelectorInBackground:@selector(crash) withObject:nil];
}
-(void)crash {
[NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
abort();
}
Run Code Online (Sandbox Code Playgroud)
相当令人困惑的是,它按预期工作.
这是怎么回事?我究竟做错了什么?
Dav*_*her 10
更新 - 2010年11月16日:当在IBAction方法中抛出异常时,这个答案存在一些问题.请改为查看此答案:
这扩展了David Gelhar的答案,以及他提供的链接.下面是我通过重写NSApplication的-reportException:方法来做到这一点.首先,为NSApplication创建一个ExceptionHandling类别(仅供参考,您应该在"ExceptionHandling"之前添加2-3个字母的缩写,以降低名称冲突的风险):
的NSApplication + ExceptionHandling.h
#import <Cocoa/Cocoa.h>
@interface NSApplication (ExceptionHandling)
- (void)reportException:(NSException *)anException;
@end
Run Code Online (Sandbox Code Playgroud)
的NSApplication + ExceptionHandling.m
#import "NSApplication+ExceptionHandling.h"
@implementation NSApplication (ExceptionHandling)
- (void)reportException:(NSException *)anException
{
(*NSGetUncaughtExceptionHandler())(anException);
}
@end
Run Code Online (Sandbox Code Playgroud)
其次,在NSApplication的委托中,我做了以下事情:
AppDelegate.m
void exceptionHandler(NSException *anException)
{
NSLog(@"%@", [anException reason]);
NSLog(@"%@", [anException userInfo]);
[NSApp terminate:nil]; // you can call exit() instead if desired
}
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
NSSetUncaughtExceptionHandler(&exceptionHandler);
// additional code...
// NOTE: See the "UPDATE" at the end of this post regarding a possible glitch here...
}
Run Code Online (Sandbox Code Playgroud)
terminate:您可以拨打电话,而不是使用NSApp exit().terminate:更多的是Cocoa-kosher,尽管你可能想要applicationShouldTerminate:在抛出异常的情况下跳过你的代码并且只是硬崩溃exit():
#import "sysexits.h"
// ...
exit(EX_SOFTWARE);
Run Code Online (Sandbox Code Playgroud)
每当抛出异常时,在主线程上,并且它没有被捕获和销毁,现在将调用自定义未捕获异常处理程序而不是NSApplication.这允许您使应用程序崩溃等.
上面的代码似乎有一个小故障.在NSApplication完成调用其所有委托方法之后,您的自定义异常处理程序将不会"启动"并继续工作.这意味着如果你在applicationWillFinishLaunching:或applicationDidFinishLaunching:或awakeFromNib:中执行一些设置代码,默认的NSApplication异常处理程序似乎在完全初始化之后才会进行.
这意味着如果你这样做:
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
NSSetUncaughtExceptionHandler(&exceptionHandler);
MyClass *myClass = [[MyClass alloc] init]; // throws an exception during init...
}
Run Code Online (Sandbox Code Playgroud)
您的exceptionHandler不会获得异常.NSApplication会,它只会记录它.
要解决此问题,只需将任何初始化代码放在@try/@catch/@finally块中,您就可以调用自定义的exceptionHandler:
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
NSSetUncaughtExceptionHandler(&exceptionHandler);
@try
{
MyClass *myClass = [[MyClass alloc] init]; // throws an exception during init...
}
@catch (NSException * e)
{
exceptionHandler(e);
}
@finally
{
// cleanup code...
}
}
Run Code Online (Sandbox Code Playgroud)
现在你exceptionHandler()获得异常并可以相应地处理它.在NSApplication完成调用所有委托方法之后,NSApplication + ExceptionHandling.h类别启动,通过其自定义-reportException:方法调用exceptionHandler().此时,当您希望将异常引发到Uncaught Exception Handler时,您不必担心@ try/@ catch/@ finally.
造成这种情况的原因令我感到困惑.可能是API中幕后的东西.即使我将NSApplication子类化,而不是添加类别,也会发生这种情况.此外,可能还有其他警告.
事实证明这是一个非常简单的解决方案:
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }];
如果您使用它,它不会使您的应用程序崩溃@try ... @catch.
我无法想象为什么这不是默认值.