Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa 为什么提出NSException不会导致我的应用程序失败?_Cocoa_Exception_Multithreading_Crash_Raise - Fatal编程技术网

Cocoa 为什么提出NSException不会导致我的应用程序失败?

Cocoa 为什么提出NSException不会导致我的应用程序失败?,cocoa,exception,multithreading,crash,raise,Cocoa,Exception,Multithreading,Crash,Raise,问题 #import "NSApplication+ExceptionHandling.h" @implementation NSApplication (ExceptionHandling) - (void)reportException:(NSException *)anException { (*NSGetUncaughtExceptionHandler())(anException); } @end void exceptionHandler(NSException *a

问题

#import "NSApplication+ExceptionHandling.h"

@implementation NSApplication (ExceptionHandling)

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

@end
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...
}
我正在编写一个Cocoa应用程序,我想提出一些异常,这些异常会导致应用程序崩溃

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

[NSException raise:NSInternalInconsistencyException format:@"This should crash the application."];
abort();
问题是,它们不会关闭应用程序-消息只是记录到控制台,应用程序会以愉快的方式进行

据我所知,例外的全部意义在于,他们是在特殊情况下被解雇的。在这种情况下,我希望应用程序以明显的方式退出。但这并没有发生

我尝试过的

我试过:

-(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();
}
令人困惑的是,它的工作原理与预期相符


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

我发布了这个问题和答案,我希望有人在大约一年前告诉我:

在主线程上抛出的异常被NSApplication捕获。

我从头到尾浏览了NSException上的文档,没有提到我能回忆起来的内容。我知道这一点的唯一原因是因为神奇的可可开发:

解决方案。我猜。


我有一个没有UI的守护进程,它几乎完全在主线程上运行。我将不得不转移整个应用程序来运行后台线程,除非其他人可以建议一种方法来停止非应用程序捕获我抛出的异常。我很确定这是不可能的。

也许你可以使用,或者在非应用程序上创建一个覆盖的类别,正如更新-2010年11月16日所建议的那样:

在iAction方法中抛出异常时,这个答案会出现一些问题。请参见以下答案:


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

n应用程序+例外处理.h

#import <Cocoa/Cocoa.h>

@interface NSApplication (ExceptionHandling)

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

@end

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

AppDelegate.m

#import "NSApplication+ExceptionHandling.h"

@implementation NSApplication (ExceptionHandling)

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

@end
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:
更为洁净,但如果引发异常并使用
exit()
硬崩溃,您可能希望跳过
应用程序shouldTerminate:
代码:


无论何时在主线程上抛出异常,并且该异常未被捕获和销毁,您的自定义未捕获异常处理程序现在将被调用,而不是NSApplication的。这允许您使应用程序崩溃,以及其他一些事情


更新: 上面的代码似乎有一个小故障。在NSApplication完成调用其所有委托方法之前,您的自定义异常处理程序不会“启动”并工作。这意味着,如果您在应用程序内部执行一些设置代码,则将完成启动:应用程序IDFinishLaunching:从NIB:唤醒,默认的NSApplication异常处理程序在完全初始化之前似乎一直在运行

这意味着如果你这样做:

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

        MyClass *myClass = [[MyClass alloc] init];   // throws an exception during init...
}
您的异常处理程序将不会获得异常。非应用程序会,它只会记录它

要解决此问题,只需将任何初始化代码放入
@try/@catch/@finally
块中,您就可以调用自定义的异常处理程序

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


我对造成这种情况的原因感到有点困惑。可能是API中的一些幕后操作。即使我将NSApplication子类化,而不是添加一个类别,它也会发生。这可能还附带了其他警告。

我正试图正确理解这一点:为什么下面的非应用程序分类方法会导致无限循环?在该无限循环中,“引发了未捕获异常”被无限次注销:

- (void)reportException:(NSException *)anException
{
    // handle the exception properly
    (*NSGetUncaughtExceptionHandler())(anException);
}
为了测试(和理解目的),这是我唯一要做的事情,也就是说,只需创建上面的category方法。(根据中的说明)

为什么这会导致无限循环?这与默认的未捕获异常处理程序方法应该做的不一致,即只记录异常并退出程序。(见附件)

是否默认的未捕获异常处理程序实际上再次抛出异常,从而导致这个无限循环

注意:我知道只创建这个分类方法是愚蠢的。这样做的目的是为了更好地理解


更新:没关系,我想我现在明白了。这是我的照片。我们知道,默认情况下,NSApplication的reportException:方法记录异常。但是,根据文档,默认的未捕获异常处理程序记录异常并存在于程序中。但是,为了更精确,文档中应该这样表述:默认的未捕获异常处理程序调用NSApplication的reportException:方法(为了记录它,该方法的默认实现确实会这样做),然后存在程序。因此,现在应该清楚了,为什么在重写的reportException:中调用默认的未捕获异常处理程序会导致无限循环:前者调用后者

结果是一个非常简单的解决方案: