为什么引发 NSException 不会导致我的应用程序崩溃? [英] Why is raising an NSException not bringing down my application?

查看:24
本文介绍了为什么引发 NSException 不会导致我的应用程序崩溃?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

我正在编写一个 Cocoa 应用程序,我想引发异常,使应用程序崩溃.

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

我的应用程序委托中有以下几行:

I have the following lines in my application delegate:

[NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
abort();

问题是,他们并没有关闭应用程序 - 消息只是记录到控制台,应用程序继续它的快乐方式.

The problem is, they don't bring down the application - the message is just logged to the console and the app carries on it's merry way.

据我了解,例外的全部意义在于它们是在特殊情况下被解雇的.在这种情况下,我希望应用程序以一种明显的方式退出.这不会发生.

As I understand it, the whole point of exceptions is that they're fired under exceptional circumstances. In these circumstances, I want the application to quit in an obvious way. And this doesn't happen.

我的尝试

我试过了:

-(void)applicationDidFinishLaunching:(NSNotification *)note
    // ...
    [self performSelectorOnMainThread:@selector(crash) withObject:nil waitUntilDone:YES];
}

-(void)crash {
    [NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
    abort();
}

这不起作用并且

-(void)applicationDidFinishLaunching:(NSNotification *)note
    // ...
    [self performSelectorInBackground:@selector(crash) withObject:nil];
}

-(void)crash {
    [NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
    abort();
}

令人困惑的是,它按预期工作.

which, rather confusingly, works as expected.

发生了什么事?我做错了什么?

What's going on? What am I doing wrong?

推荐答案

更新 - 2010 年 11 月 16 日:当 IBAction 方法中引发异常时,此答案存在一些问题.请参阅此答案:

UPDATE - Nov 16, 2010: There are some issues with this answer when exceptions are thrown inside IBAction methods. See this answer instead:

如何阻止 HIToolbox 捕获我的例外?

这扩展了 David Gelhar 的 答案以及他提供的链接.下面是我如何通过覆盖 NSApplication 的 -reportException: 方法来实现的.首先,为 NSApplication 创建一个 ExceptionHandling 类别(仅供参考,您应该在ExceptionHandling"之前添加一个 2-3 个字母的首字母缩写词,以减少名称冲突的风险):

This expands on David Gelhar's answer, and the link he provided. Below is how I did it by overriding NSApplication's -reportException: method. First, create an ExceptionHandling Category for NSApplication (FYI, you should add a 2-3 letter acronym before "ExceptionHandling" to reduce the risk of name clashing):

NSApplication+ExceptionHandling.h

#import <Cocoa/Cocoa.h>

@interface NSApplication (ExceptionHandling)

- (void)reportException:(NSException *)anException;

@end

NSApplication+ExceptionHandling.m

#import "NSApplication+ExceptionHandling.h"

@implementation NSApplication (ExceptionHandling)

- (void)reportException:(NSException *)anException
{
    (*NSGetUncaughtExceptionHandler())(anException);
}

@end

<小时>

其次,在 NSApplication 的委托中,我做了以下事情:


Second, inside NSApplication's delegate, I did the following:

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...
}

您可以调用 exit() 而不是使用 NSApp 的 terminate:.terminate: 更符合 Cocoa-kosher 标准,但您可能希望跳过 applicationShouldTerminate: 代码,以防引发异常并使用 exit():

Rather than use NSApp's terminate:, you can call exit() instead. terminate: is more Cocoa-kosher, though you may want to skip your applicationShouldTerminate: code in the event an exception was thrown and simply hard-crash with exit():

#import "sysexits.h"

// ...

exit(EX_SOFTWARE);

<小时>

每当在主线程上抛出异常并且它没有被捕获和销毁时,现在将调用您的自定义未捕获异常处理程序而不是 NSApplication 的.这使您可以使您的应用程序崩溃,等等.


Whenever an exception is thrown, on the main thread, and it's not caught and destroyed, your custom uncaught exception handler will now be called instead of NSApplication's. This allows you to crash your application, among other things.

上面的代码似乎有一个小故障.在 NSApplication 完成调用其所有委托方法之前,您的自定义异常处理程序不会启动"并工作.这意味着如果您在 applicationWillFinishLaunching:applicationDidFinishLaunching:awakeFromNib: 中执行一些设置代码,默认的 NSApplication 异常处理程序似乎在-播放直到它完全初始化.

There appears to be a small glitch in the above code. Your custom exception handler won't "kick in" and work until after NSApplication has finished calling all of its delegate methods. This means that if you do some setup-code inside applicationWillFinishLaunching: or applicationDidFinishLaunching: or awakeFromNib:, the default NSApplication exception handler appears to be in-play until after it's fully initialized.

这意味着如果你这样做:

What that means is if you do this:

- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
        NSSetUncaughtExceptionHandler(&exceptionHandler);

        MyClass *myClass = [[MyClass alloc] init];   // throws an exception during init...
}

您的 exceptionHandler 不会得到异常.NSApplication 会,它只会记录它.

Your exceptionHandler won't get the exception. NSApplication will, and it'll just log it.

要解决这个问题,只需将任何初始化代码放在 @try/@catch/@finally 块中,您就可以调用自定义 exceptionHandler:

To fix this, simply put any initialization code inside a @try/@catch/@finally block and you can call your custom 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...
    }
}

现在您的 exceptionHandler() 获取异常并可以相应地处理它.在 NSApplication 调用完所有委托方法后,NSApplication+ExceptionHandling.h 类别启动,通过其自定义的 -reportException: 方法调用 exceptionHandler().此时,当您希望将异常引发到您的未捕获异常处理程序时,您不必担心@try/@catch/@finally.

Now your exceptionHandler() gets the exception and can handle it accordingly. After NSApplication has finished calling all delegate methods, the NSApplication+ExceptionHandling.h Category kicks in, calling exceptionHandler() through its custom -reportException: method. At this point you don't have to worry about @try/@catch/@finally when you want exceptions to raise to your Uncaught Exception Handler.

我对造成这种情况的原因感到有些困惑.可能是 API 的幕后工作.即使我将 NSApplication 子类化,而不是添加一个类别,它也会发生.可能还有其他注意事项.

I'm a little baffled by what is causing this. Probably something behind-the-scenes in the API. It occurs even when I subclass NSApplication, rather than adding a category. There may be other caveats attached to this as well.

这篇关于为什么引发 NSException 不会导致我的应用程序崩溃?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆