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, которые были в мутации во время броска и которые лежат между броском и уловом, так же хорошо, как неопределенное поведение.Проблема в том, что вы не представляете, что это за память (в большинстве случаев и в течение разумного времени обслуживания).Исключения в C ++ хорошо определены, и они правильно раскручиваются (например, вызываются деструкторы) - но попытка продолжить в контексте ObjC игнорирует любые последствия неопределенного поведения.ИМО, они должны существовать только для ObjC ++ (потому что C ++ требует их).
В идеальном мире ваши программы ObjC и используемые вами библиотеки не будут использовать исключения (вообще).Поскольку вы используете библиотеки, которые действительно генерируют (включая Cocoa), устанавливайте обработчик исключений верхнего уровня , только если вам нужна специальная информация об ошибке .Если API требует, чтобы вы ожидали исключение из-за обстоятельств, не зависящих от вас, и вы должны восстановить , тогда напишите перехват, но немедленно преобразуйте эту логику в обычный программный поток (например, NSError
) -Вам никогда не нужно писать свой собственный бросок.-[NSArray objectAtIndex:
и «объект не отвечает селектору» являются примерами ошибок программиста - они должны не быть обнаружены, но программа должна быть исправлена.