0) Избегайте исключений в Какао. Как правило, они не подлежат восстановлению. Вы можете поймать их для собственного сообщения об ошибках, но обычно небезопасно предполагать, что вы сможете исправить их.
1) Если вам нужно поймать, ловите его немедленно. Не пишите свои собственные броски - вместо этого преобразуйте его во что-то вроде NSError
и передайте его. NSError
может содержать всю информацию, необходимую для отображения или отправки кода ошибки, а также локализованное сообщение.
2) Вы не можете преобразовать NSException
в NSError
(напрямую), потому что NSException
не имеет всех свойств, которыми обладает NSError
- это другое представление данных. Во-первых, код ошибки недоступен. Во-вторых, описание не локализовано. Лучшее, что вы можете сделать, - это создать код ошибки и домен, затем использовать необходимые свойства из NSException
и сохранить их в NSError
. Это может выглядеть примерно так:
// error checking omitted
extern NSString* const MONExceptionHandlerDomain;
extern const int MONNSExceptionEncounteredErrorCode;
NSError * NewNSErrorFromException(NSException * exc) {
NSMutableDictionary * info = [NSMutableDictionary dictionary];
[info setValue:exc.name forKey:@"MONExceptionName"];
[info setValue:exc.reason forKey:@"MONExceptionReason"];
[info setValue:exc.callStackReturnAddresses forKey:@"MONExceptionCallStackReturnAddresses"];
[info setValue:exc.callStackSymbols forKey:@"MONExceptionCallStackSymbols"];
[info setValue:exc.userInfo forKey:@"MONExceptionUserInfo"];
return [[NSError alloc] initWithDomain:MONExceptionHandlerDomain code:MONNSExceptionEncounteredErrorCode userInfo:info];
}
@catch (NSException * exc) {
NSError * err = NewNSErrorFromException(exc);
...
}
Если API-интерфейсы, которые вы используете, генерируют исключения, которые вы, как ожидается, поймаете и восстановите (например, не совсем исключительные случаи), тогда да, вы можете поймать и попытаться продолжить. К сожалению, любой, кто пишет исключения в Какао с намерением, что вы их поймаете, вероятно, не понимает проблемы достаточно хорошо, чтобы реализовать надежную реализацию размотки (например, даже если она вызывает утечки, это не надежно).
3) На самом деле сейчас не время и не место для отображения предупреждения. Если вы устанавливаете обработчик исключений верхнего уровня (через NSSetUncaughtExceptionHandler
) - вы должны просто зарегистрировать сообщение - тогда обработчик исключений будет прерван. Ваше приложение находится в нестабильном состоянии - продолжить хуже, чем прервать работу. Возможно, вы захотите отправить эти настраиваемые сообщения домой, лучше сделать это при следующем запуске вашего приложения.
4) В большинстве случаев ваше приложение находится в нестабильном состоянии, и вам не следует продолжать работу. Но, чтобы на самом деле ответить на этот вопрос для этих угловых случаев: «Да, вы можете восстановиться и продолжить, когда поймаете, но вам следует пытаться восстановить и продолжить, только когда бросающий API сообщает, что восстановление поддерживается. Если проблема не зависит от вас, и проблема не является исключительной (например, файл не найден), и поставщик действительно ожидает, что вы продолжите, тогда я должен предположить, что они ожидают, что вы продолжите, даже если это действительно не (100% безопасно). ». Не пытайтесь восстановить / продолжить работу из обработчика исключений верхнего уровня (программа будет прервана после возврата). Если вы хотите изящно представить это сразу на OSX, лучше всего подойдет другой процесс. Если вы вызываете через чистый интерфейс C ++, то раскрутка четко определена, и необходимость перехвата необходима - продолжайте, если это можно восстановить. Исключения в C ++ могут быть исправлены и хорошо определены - они также используются довольно широко (включая не исключительные условия).
(IMO ...) Исключения в ObjC не следовало вводить, и любой метод, который генерируется из системных или сторонних библиотек, должен быть устаревшим. Они не раскручиваются хорошо или четко. Кроме того, разворачивающиеся потоки против обычного потока программы Какао. Это означает, что касание любой памяти / отношений объекта objc, которые были в мутации во время выброса и которые лежат между выбросом и захватом, ничем не хуже поведения undefined. Проблема в том, что вы не знаете, что это за память (в большинстве случаев и в разумные сроки). Исключения C ++ четко определены, и они корректно раскручиваются (например, вызываются деструкторы), но попытка продолжить в контексте ObjC игнорирует любые последствия неопределенного поведения. IMO, они должны существовать только для ObjC ++ (потому что C ++ требует их).
В идеальном мире ваши программы ObjC и библиотеки, которые вы используете, не будут использовать исключения (вообще). Поскольку вы используете библиотеки, которые генерируют выбросы (включая Какао), устанавливайте обработчик исключений верхнего уровня только в том случае, если вам нужна особая информация об ошибке. Если API требует, чтобы вы могли ожидать возникновения исключения из-за обстоятельств, не зависящих от вас, и ожидается восстановление, тогда напишите уловку, но немедленно преобразуйте эту логику в нормальный поток программы (например, NSError
) - вы никогда не нужно писать свой собственный бросок. -[NSArray objectAtIndex:
и «объект не реагирует на селектор» являются примерами ошибок программиста - их не следует не отлавливать, но программу следует исправить.
person
justin
schedule
06.12.2011