Обработка исключений во всем приложении - PullRequest
3 голосов
/ 06 декабря 2011

У меня есть несколько сомнений относительно обработки исключений в iPhone.Вот они:

  1. Предположим, у меня есть цепочка методов, которые вызываются один за другим, то есть метод A вызывает метод B, который в свою очередь вызывает метод C, который вызываетметод D. Как лучше всего разместить блок try-catch (метод A или B или C или D или все).Кроме того, мне нужно отобразить предупреждение для пользователя о том, что произошло исключение, а затем я хочу записать это исключение на свой сервер.Итак, если я пишу свой блок try - catch во всех этих методах и если исключение происходит в методе D;тогда я думаю, что предупреждение будет отображаться 4 раза, а веб-сервис для регистрации также будет вызываться 4 раза (до тех пор, пока управление не достигнет перехватить блок метода A).Итак, я должен просто использовать @throw;в блоке catch метода B, C и D и напишите мою логику в блоке catch метода A (метод верхнего уровня) или я должен избегать написания try - catch вообще в методах B, C и D.

  2. Мне нужен какой-то код ошибки из исключения (потому что моему веб-сервису нужны параметры код ошибки и описание).Можно ли преобразовать исключение в ошибку или мне нужно будет жестко закодировать этот код?

  3. Я где-то читал о NSSetUncaughtExceptionHandler.И я думаю, если я смогу установить этот обработчик (в методе appDidFinishLaunching делегата приложения) и в методе обработчика, если я покажу пользователю некоторое предупреждение и вызову веб-службу;тогда мне не нужно писать блок try-catch в каждом из моих методов, в каждом из моих классов.Прав ли я ??

  4. Если возникла исключительная ситуация, и я написал либо блок try-catch, либо NSSetUncaughtExceptionHandler, мое приложение продолжит работу или оно не будет отвечать ни на один изпользовательские события.(Я уверен, что он справится с аварией. Я хочу знать, будет ли он зависать)

Кто-то, пожалуйста, просветите меня в этой ТЕМЕ ИСКЛЮЧЕНИЯ.

1 Ответ

18 голосов
/ 06 декабря 2011

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: и «объект не отвечает селектору» являются примерами ошибок программиста - они должны не быть обнаружены, но программа должна быть исправлена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...