我如何停止HIToolbox捕获我的例外? [英] How can I stop HIToolbox from catching my exceptions?

查看:287
本文介绍了我如何停止HIToolbox捕获我的例外?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的另一个问题是关于的问题为什么我的应用程序不会因为例外而被关闭



问题



当主线程通过Action发生异常时,该应用仍然不会崩溃。



根据解答我原来的问题,我已经实现了reportException类别NSApplication并设置未捕获的异常处理程序。



代码



以下在我的应用程序代理中,我已经连接到我的UI中的按钮进行测试。

   - (IBAction) crashOnMainThread:(id)sender {
[self performSelectorOnMainThread:@selector(crash)withObject:nil waitUntilDone:YES];
}

- (void)crash {
//测试异常处理
[NSException raise:NSInternalInconsistencyException format:@这应该会崩溃应用程序。 ];
}

当我按下按钮时,我的应用程序不会崩溃。当我看着控制台日志时,我看到:

  06/09/2010 14:12:25 EHTest1 [26384] HIToolbox:忽略异常'这应该会崩溃的应用程序。'内部的事件调度

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(NSThreadPerformAddit离子)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 **





这表明对于任何操作代码,您需要立即在后台线程中运行它,以便将任何异常注册为未注册。咦?我没有看到任何类似这样的代码。



我尝试过的



延迟崩溃应用程序,因此未连接到UI元素。它崩溃了。



我已经尝试在我的应用程序委托中安装了一个自定义的NSExceptionHandler:

   - (BOOL)exceptionHandler:(NSExceptionHandler *)sender 
shouldHandleException:(NSException *)exception
mask:(unsigned int)aMask {
abort();
返回YES;
}

- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
NSExceptionHandler * handler = [NSExceptionHandler defaultExceptionHandler];
[处理程序setExceptionHandlingMask:NSLogAndHandleEveryExceptionMask];
[handler setDelegate:self];
}

这里的问题是每个异常都崩溃,无论是否被捕获。



如果我尝试检查掩码,并且不会在捕获到的异常时崩溃,我回到正方形1,因为HIToolbox正好捕获异常



问题




  • 如何停止HIToolbox捕获异常,以便我的应用程序使用未捕获的异常处理程序和崩溃?

  • 可以运行与相同调用堆栈中的代码一种行为?当然这可以吗?

  • 如果不行,可以选择什么?



驱赶我的墙,所以任何帮助将不胜感激。

解决方案

我回答了你关于这个问题的最后一个问题,与Carbon的HIToolbox捕获由IBActions抛出的异常相同的问题。



首先,撤消我在以前的答案。由于某种原因,它不能与IBActions一起使用。我的希望是,HIToolbox在异常处理链中的比例较低,并在NSApplication有机会之前获得任何IBAction / GUI异常。任何可以使用 NSSetUncaughtExceptionHandler()注册的自定义异常处理函数在链条的顶部生活(我相信)。




  1. ExceptionHandling.framework 添加到您的Xcode中项目

  2. #importExceptionHandlerDelegate.h到您的AppDelegate.m(或自定义Singleton异常类)

Inside AppDelegate.m

  //非常第一个消息发送到类
+(void)initialize
{
NSExceptionHandler * exceptionHandler = [NSExceptionHandler defaultExceptionHandler];
unsigned int handlingMask = NSLogAndHandleEveryExceptionMask;
[exceptionHandler setExceptionHandlingMask:handlingMask];
[exceptionHandler setDelegate:self];

// ...
}


#pragma mark -
#pragma mark NSExceptionHandler代理方法

//调用1st:NSExceptionHandler是否记录异常?
- (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldLogException:(NSException *)异常掩码:(unsigned int)aMask
{
// ...日志NSException如果需要...

return NO; //如果NSExceptionHandler应该处理日志记录,则更改为YES


//调用2nd:NSExceptionHandler是否处理异常?
- (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldHandleException:(NSException *)异常掩码:(unsigned int)aMask
{
// ...崩溃你的应用程序在这里(例如[ NSApp终止:self];)

// ...或处理NSException并相应地返回YES / NO

return NO; //如果应用程序崩溃,永远不会返回 - 应该在
之前崩溃

code> NSLogAndHandleEveryExceptionMask 标志告诉NSExceptionHandler捕获每个可能的异常(仅适用于您的应用程序,我相信),无论它存在于哪个异常链上。



这意味着 @ catch / @ try / @ finally 块将无法正常工作,因为 NSHandleOtherExceptionMask 标志告知NSExceptionHandler在异常处理程序链上捕获下面的一切。您可以删除该标志,但是HIToolKit可能会再次获得任何IBAction异常,因为它在链上似乎较低。



Apple的文档有关于标志的信息:



所以当NSException被引发(你的应用程序AFAIK中的任何地方),并且NSLogAndHandleEveryExceptionMask被设置时,这些在委托中被调用 - order:


  1. -exceptionHandler:shouldLogException:mask: / li>
  2. -exceptionHandler:shouldHandleException:mask:被称为第二个。

只要把你的崩溃代码放在第二个委托方法中,你应该可以。






有用的文章:了解Cocoa中的异常和处理程序






我认为您无法使NSExceptionHandler的委托工作的原因是因为它与 NSSetUncaughtExceptionHandler(),这是我上一个问题的答案的一部分。 per 苹果


NSExceptionHandler类提供
监控设备和
调试
Objective-C程序中的特殊条件。它通过
通过
NSSetUncaughtExceptionHandler
函数安装一个特殊未捕获的
异常处理程序。因此,要使用NSExceptionHandler的
服务,您
不得安装您自己的自定义
未捕获的异常处理程序。




当您覆盖NSApplication的 -reportException:方法时,也可能无法正常工作。



最后,似乎没有必要使用@ catch / @ try / @ finally(也是我以前的答案的一部分)。在 + initialize 中配置NSExceptionHandler似乎立即踢,不像覆盖NSApplication的 -reportException:方法。


This question follows on from my other question on why my app isn't being brought down by exceptions.

The Problem

When an exception is thrown on the main thread via an Action, the app still doesn't crash.

As per Dave's answer to my original question, I've implemented the reportException category on NSApplication and set the uncaught exception handler.

Code

I've got the following in my app delegate, which I've hooked up to a button in my UI to test.

-(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."];
}

When I press the button, my app doesn't crash. When I look at the console log, I see this:

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

It looks like Carbon is catching the exception, which is really annoying.

This suggests that for any action code, you need to immediately run it in a background thread so any exceptions are registered as uncaught. Huh? I've not seen any code that's structured like this.

What I've tried

Crashing the app with a delay so it's not connected to a UI element. It crashes fine.

I've tried installing a custom NSExceptionHandler using this in my app delegate:

-(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];
}

the problem here is it crashes on every exception, whether it's caught or not.

If I try and check the mask and don't crash on a caught exception, I'm back to square 1 as it seems that HIToolbox catches the exception in exactly the same way as a try/catch block would.

Questions

  • How can I stop HIToolbox catching the exceptions so that my app uses the uncaught exception handler and crashes?
  • Is it OK to be running code that's in the same call stack as an action? Surely this is OK?
  • If it's not OK, what's the alternative?

This is driving me up the wall, so any help would be much appreciated.

解决方案

I answered your last question on this subject, and ran into the same problem with Carbon's HIToolbox catching exceptions thrown by IBActions.

First, undo everything I mentioned in my previous answer. It doesn't work with IBActions for some reason. My hunch is that HIToolbox lives lower on the exception-handling-chain, and gets any IBAction/GUI exceptions before NSApplication has the opportunity to. Any custom exception-handling function you can register with NSSetUncaughtExceptionHandler() lives (I believe) at the top of the chain.

You're on the right track with NSExceptionHandling:

  1. Add the ExceptionHandling.framework to your Xcode Project
  2. #import "ExceptionHandlerDelegate.h" into your AppDelegate.m (or a custom Singleton exception class)

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

The NSLogAndHandleEveryExceptionMask flag tells NSExceptionHandler to capture every exception it can (for your app only, I believe), regardless of where on the exception chain it exists.

This means that @catch/@try/@finally blocks won't work, because the NSHandleOtherExceptionMask flag tells NSExceptionHandler to capture "everything below it" on the exception-handler chain. You can remove that flag, but then HIToolKit will probably get any IBAction exceptions again, since it appears to be lower on said chain.

Apple's docs have info about the flags: NSExceptionHandler docs

So when an NSException is raised (anywhere in your app AFAIK), and NSLogAndHandleEveryExceptionMask is set, these are called in the delegate in-order:

  1. -exceptionHandler:shouldLogException:mask: is called first.
  2. -exceptionHandler:shouldHandleException:mask: is called second.

Just put your "crash code" inside the second delegate method and you should be OK.


Helpful article: Understanding Exceptions and Handlers in Cocoa


The reason I think you were having trouble getting NSExceptionHandler's delegate to work is because it's NOT compatible with a custom method set with NSSetUncaughtExceptionHandler(), which was part of the answer in my previous question. Per Apple:

The NSExceptionHandler class provides facilities for monitoring and debugging exceptional conditions in Objective-C programs. It works by installing a special uncaught exception handler via the NSSetUncaughtExceptionHandler function. Consequently, to use the services of NSExceptionHandler, you must not install your own custom uncaught exception handler.

It also probably doesn't work well when you override NSApplication's -reportException: method.

Lastly, there doesn't appear to be a need to use @catch/@try/@finally (also part of my previous answer). Configuring NSExceptionHandler inside +initialize appears to "kick in" immediately, unlike overriding NSApplication's -reportException: method.

这篇关于我如何停止HIToolbox捕获我的例外?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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