Как я могу остановить HIToolbox от перехвата моих исключений? - PullRequest
4 голосов
/ 06 сентября 2010

Этот вопрос вытекает из моего другого вопроса , почему мое приложение не отключается из-за исключений .

Проблема

Когда исключение генерируется в главном потоке через действие, приложение по-прежнему не падает.

Согласно ответу Дейва на мой первоначальный вопрос , я реализовал категорию reportException дляNSApplication и установите обработчик необработанных исключений.

Код

В моем делегате приложения есть следующее, которое я подключил к кнопке в своем пользовательском интерфейседля проверки.

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

Когда я нажимаю кнопку, мое приложение не падает.Когда я смотрю на журнал консоли, я вижу это:

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

Похоже, что Carbon ловит исключение, которое действительно раздражает.

Это говорит о том, что для любого кода действия вам необходимо немедленно запустить его в фоновом потоке, чтобы любые исключения были зарегистрированы как необработанные.А?Я не видел ни одного кода, который имеет такую ​​структуру.

Что я пробовал

Сбой приложения с задержкой, чтобы оно не подключалось к элементу пользовательского интерфейса.Он нормально падает.

Я пытался установить пользовательский NSExceptionHandler, используя это в моем делегате приложения:

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

проблема здесь в том, что он падает при каждом исключении, независимо от того, перехвачено оно или нет.

Если я попытаюсь проверить маску и не потерпеть крах на пойманном исключении, я вернусь к квадрату 1, так как кажется, что HIToolbox ловит исключение точно так же, как это делал бы блок try / catch.

Вопросы

  • Как мне остановить HIToolbox, перехватывающий исключения, чтобы мое приложение использовало обработчик необработанных исключений и зависало?
  • это нормально для выполнения кода, который находится в том же стеке вызовов, что и действие?Конечно, это нормально?
  • Если все не в порядке, какая альтернатива?

Это приводит меня к стене, поэтому любая помощь будет очень признательна.

Ответы [ 2 ]

6 голосов
/ 17 ноября 2010

Я ответил на ваш последний вопрос на эту тему и столкнулся с той же проблемой, что и исключения Carbon HIToolbox, генерируемые IBActions.

Во-первых, отмените все, что я упомянул в моем предыдущем ответе . По некоторым причинам он не работает с IBActions. Я догадываюсь, что HIToolbox ниже в цепочке обработки исключений и получает любые исключения IBAction / GUI, прежде чем NSApplication сможет это сделать. Любая пользовательская функция обработки исключений, которую вы можете зарегистрировать в NSSetUncaughtExceptionHandler() жизнях (я считаю) в верхней части цепочки.

Вы на правильном пути с NSExceptionHandling:

  1. Добавьте ExceptionHandling.framework в ваш проект Xcode
  2. #import "ExceptionHandlerDelegate.h" в ваш AppDelegate.m (или пользовательский класс исключений Singleton)

Внутри 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
}

Флаг NSLogAndHandleEveryExceptionMask указывает NSExceptionHandler перехватывать каждое исключение, которое оно может (я полагаю, только для вашего приложения), независимо от того, где в цепочке исключений оно существует.

Это означает, что блоки @ catch / @ try / @ finally не будут работать, поскольку флаг NSHandleOtherExceptionMask указывает NSExceptionHandler захватывать «все, что находится ниже» в цепочке обработчиков исключений. Вы можете удалить этот флаг, но тогда HIToolKit, вероятно, снова получит любые исключения IBAction, так как он кажется ниже в указанной цепочке.

Документы Apple содержат информацию о флагах: NSExceptionHandler docs

Таким образом, когда NSException повышается (где-нибудь в вашем приложении AFAIK), и NSLogAndHandleEveryExceptionMask установлен, они вызываются в делегате по порядку:

  1. -exceptionHandler:shouldLogException:mask: вызывается первым.
  2. -exceptionHandler:shouldHandleException:mask: называется вторым.

Просто поместите свой «код аварии» во второй метод делегата, и все будет в порядке.


Полезная статья: Понимание исключений и обработчиков в какао


Причина, по которой я думаю, что у вас возникли проблемы с работой делегата NSExceptionHandler, заключается в том, что он НЕ совместим с пользовательским методом, установленным с NSSetUncaughtExceptionHandler(), что было частью ответа в моем предыдущем вопросе. За Apple :

Класс NSExceptionHandler предоставляет средства для мониторинга и отладка исключительных условий в Программы Objective-C. Это работает установка специального необученного обработчик исключений через NSSetUncaughtExceptionHandler функция. Следовательно, чтобы использовать услуги NSExceptionHandler, вы не должен устанавливать свой собственный кастом необработанный обработчик исключений.

Это также, вероятно, не работает, когда вы переопределяете метод -reportException: NSApplication.

И, наконец, нет необходимости использовать @ catch / @ try / @ finally (также часть моего предыдущего ответа). Конфигурирование NSExceptionHandler внутри +initialize, по-видимому, сразу «включается», в отличие от переопределения метода -reportException: NSApplication.

1 голос
/ 07 сентября 2010

Вы не можете надежно. Бросать исключения через границы API не поддерживается, если это явно не задокументировано (и я не могу думать ни о каких случаях, которые явно задокументированы).

...