为什么提高一个NSException不会导致我的应用程序? [英] Why is raising an NSException not bringing down my application?

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

问题描述

问题



我正在写一个Cocoa应用程序,我想提出异常,会使应用程序崩溃。



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

  [NSException raise: NSInternalInconsistencyException format:@这应该会导致应用程序崩溃。 
abort();

问题是,他们没有打开应用程序 - 消息只是记录到控制台



根据我的理解,整个例外是他们在特殊情况下被解雇了。在这种情况下,我希望应用程序以明显的方式退出。这不会发生。



我尝试了



've tried:

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

- (void)crash {
[NSException raise:NSInternalInconsistencyException format:@这会使应用程序崩溃。
abort();
}

无效,

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

- (void)crash {
[NSException raise:NSInternalInconsistencyException format:@这会导致应用程序崩溃。
abort();
}

这是令人困惑的工作原理。



发生了什么事?

解决方案

更新 - 2010年11月16日:这个答案当IBAction方法中抛出异常。请参阅以下答案:



如何停止HIToolbox捕获异常?






此操作会在 David Gelhar的答案及其提供的链接中展开。下面是我如何通过重写NSApplication的 -reportException:方法。首先,为NSApplication创建一个ExceptionHandling类别(FYI,您应该在ExceptionHandling之前添加一个2-3个字母的缩写,以减少名称冲突的风险):



NSApplication + ExceptionHandling.h

  #import< Cocoa / Cocoa.h> 

@interface NSApplication(ExceptionHandling)

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

@end

NSApplication + ExceptionHandling.m

  #importNSApplication + ExceptionHandling.h

@implementation NSApplication(ExceptionHandling)

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

@end






其次,在NSApplication的委托中,我做了以下操作:



AppDelegate.m

  void exceptionHandler(NSException * anException)
{
NSLog(@%@,[anException reason]);
NSLog(@%@,[anException userInfo]);

[NSApp terminate:nil]; //如果需要可以调用exit()
}

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

//附加代码...

//注意:有关此处可能出现的故障,请参阅本文末尾的UPDATE...
}

而不是使用NSApp的 terminate:您可以调用 exit() terminate:是更多的Cocoa-kosher,虽然你可能希望跳过你的 applicationShouldTerminate:抛出和简单的硬碰撞与 exit()

  #import sysexits.h

// ...

exit(EX_SOFTWARE);






每当抛出异常时, >主线程,它不会被捕获和销毁,您的自定义未捕获异常处理程序现在将被调用,而不是NSApplication的。






UPDATE:



在上面的代码中似乎有一个小故障。您的自定义异常处理程序不会踢入并工作,直到NSApplication完成调用其所有的委托方法。这意味着,如果您在 applicationWillFinishLaunching: applicationDidFinishLaunching: awakeFromNib:中执行某些设置代码,则默认的NSApplication异常处理程序显示为



这意味着如果你这样做:

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

MyClass * myClass = [[MyClass alloc] init]; //在init期间抛出异常...
}

您的 exceptionHandler 将不会得到异常。



要解决这个问题,只需将任何初始化代码放在 @ try / @ catch / @最后阻止,您可以调用您的自定义 exceptionHandler

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

@try
{
MyClass * myClass = [[MyClass alloc] init]; //在init期间抛出异常...
}
@catch(NSException * e)
{
exceptionHandler(e);
}
@finally
{
//清理代码...
}
}
pre>

现在您的 exceptionHandler()获取异常并可以相应地处理它。 NSApplication完成调用所有委托方法之后, NSApplication + ExceptionHandling.h 类别就会启动,通过其自定义的 -reportException:方法调用exceptionHandler 。在这一点上,你不必担心@ try / @ catch / @ finally,当你想要异常提高到你的未捕获异常处理程序。



我是一个小小的困惑由什么导致这。可能是在API的幕后。它发生即使我子类NSApplication,而不是添加一个类别。可能还有其他注意事项。


The Problem

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.

What I've tried

I've tried:

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

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

which doesn't work and

-(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?

解决方案

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

How can I stop HIToolbox from catching my exceptions?


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


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

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);


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.


UPDATE:

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

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

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

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.

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天全站免登陆