Мои исключения Objective-C не приводят к завершению работы моего приложения, но Apple делает

#iphone #objective-c #ios #exception

#iPhone #objective-c #iOS #исключение

Вопрос:

В моем проекте iOS (iPhone / cocos2d) я обнаружил, что исключения, которые я создаю сам, не приводят к завершению работы приложения (они просто вызывают завершение текущей функции, что приводит к странному поведению, зависшему наполовину). Например, следующий код вызывает сбой:

 NSArray* testArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
[testArray objectAtIndex:400];
  

Когда я запускаю этот код, я получаю следующее в консоли, как и следовало ожидать:

 2011-06-07 12:55:20.421 mansion-iphone[38184:207] *** Terminating app due to
    uncaught exception 'NSRangeException', reason: '*** -[NSArray
    objectAtIndex:]: index 400 beyond bounds [0 .. 2]'
  

Однако, если я пытаюсь вызвать исключение (например, из assert), я получаю половинную остановку, если я не включил «Остановить исключения Objective-C». Для меня это нормально, но вызывает проблемы, когда мои тестировщики сообщают о проблемах — поскольку приложение не зависало, у них нет журнала сбоев, чтобы отправить мне. Вот пример исключения, которое не работает:

 NSException* e = [NSException exceptionWithName:NSInternalInconsistencyException 
        reason:[NSString stringWithFormat:@"%s %@", __PRETTY_FUNCTION__,
        [NSString stringWithFormat:@"Invalid argument"]] userInfo:nil];
[e raise];
  

Если «Остановить исключения Objective-C» отключено, это даже не вызывает сообщения на консоль — использование NSAssert вместо этого выдает мне сообщение консоли, но по-прежнему не останавливает. Итак, похоже, что исключения, сгенерированные классами Cocoa, ведут себя правильно, но исключения, созданные из моего кода, — нет.

Я проверил свой код и cocos2d и не нашел никаких блоков @try, которые, казалось бы, предотвращали исключение; у кого-нибудь есть идея?

Ответ №1:

Пользовательское исключение должно работать так же, как и другие исключения, и я смог убедиться в этом в моем собственном тестовом приложении. Некоторые вещи, которые нужно проверить:

  1. Убедитесь, что NSSetUnhandledExceptionHandler не вызывается, чтобы перехватить все необработанные исключения.
  2. Попробуйте запустить свое приложение вне отладчика.
    • Я протестировал ваш код выше, и мое приложение завершается, как и ожидалось, когда возникает исключение NSRangeException или пользовательское исключение NSException, но оно не обрабатывается.
  3. Попробуйте вызвать ваше исключение в другом месте, чтобы убедиться, что оно работает, например, в main ().

ПРИМЕЧАНИЕ: Не используйте исключения как способ управления потоком программы, поскольку они очень дороги, когда создаются в Objective-C.

Комментарии:

1. Привет, спасибо за твой ответ. Вы знаете, я не думал пробовать этот блок кода прямо внутри моего метода applicationDidFinishLaunching: , но это приводит к сбою приложения, как и ожидалось. Однако при дальнейшем внедрении в приложение (это игра, использующая библиотеку Cocos2d) то же исключение ничего не делает; мне придется провести дополнительные исследования.

2. Я также заметил, что в документах Apple говорится следующее: «Исключения в главном потоке приложения Cocoa обычно не достигают уровня обработчика неперехваченных исключений, потому что глобальный объект приложения улавливает все такие исключения». Полезно знать, хотя, опять же, иногда это работает — Я думаю, это «обычно».

3. * … они очень дорогие … » Стоимость в этом контексте не вызывает беспокойства. Их действительно не так дорого использовать. Стоимость такая же, как при создании исключения C . Реальная проблема IMO заключается в том, что программы ObjC просто не разработаны / написаны для восстановления после исключений. Использование исключений в качестве потока управления обычно приводит ко многим утечкам и другим подобным проблемам, связанным с тем, что очистка не происходит при развертывании. Другой пример: @synchronized будет правильно разматываться и разблокироваться, но я просто не вижу, чтобы разработчики ObjC действительно очищали другие механизмы блокировки вручную при разматывании.