бросить исключение в цель-с / какао

Какой лучший способ бросить исключение в target-c / cocoa?

27.11.2008 17:18:57
13 ОТВЕТОВ
РЕШЕНИЕ

Я использую [NSException raise:format:]следующим образом:

[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];
528
23.11.2012 18:18:43
Я предпочитаю этот способ, а не @throw([NSException exceptionWith…])подход, а более лаконичный.
Sam Soffes 18.06.2010 19:56:46
Обязательно прочитайте важное предупреждение от вреда ( stackoverflow.com/questions/324284/324805#324805 )
e.James 22.09.2010 02:11:23
Я вообще тоже предпочитаю это, но есть одна ошибка. Может быть, это просто моя текущая версия Xcode, но синтаксис [NSException повышение ...], похоже, не распознается синтаксическим анализатором как выходной путь из метода, который возвращает значение. При использовании этого синтаксиса я вижу предупреждение «Элемент управления может достигнуть конца функции, не являющейся пустым», но с синтаксисом @throw ([NSException exceptionWith…]) синтаксический анализатор распознает это как выход и не отображает предупреждение.
mattorb 27.08.2011 16:32:18
@mpstx Я всегда использую синтаксис throw по той причине, которую вы указали (которая по-прежнему актуальна через два года в Xcode 4.6 и, вероятно, так будет всегда). Если среда IDE распознает, что создание исключения является точкой выхода из функции, часто имеет значение, если вы хотите избежать предупреждений.
Mark Amery 29.07.2013 11:13:18
Я заметил, что блоки @ try / @ catch также приводят к ложноотрицательному значению для предупреждений «контроль достигает конца функции без void» (т. Е. Предупреждение не отображается, когда оно должно быть)
Brian Gerstle 24.03.2015 02:31:55
@throw([NSException exceptionWith…])

Xcode распознает @throwоператоры как точки выхода из функций, как returnоператоры. Использование @throwсинтаксиса позволяет избежать ошибочных предупреждений « Control может достигнуть конца не пустой функции », которые вы можете получить [NSException raise:…].

Кроме того, @throwможет использоваться, чтобы бросить объекты, которые не относятся к классу NSException.

62
30.12.2019 08:39:58
@Steph Thirion: См developer.apple.com/documentation/Cocoa/Conceptual/Exceptions/... для всех деталей. Нижняя граница? Оба будут работать, но @throw можно использовать для выброса объектов, которые не относятся к классу NSException.
e.James 27.11.2008 21:18:13

Я думаю, чтобы быть последовательным, лучше использовать @throw с вашим собственным классом, который расширяет NSException. Затем вы используете те же обозначения для try catch, наконец:

@try {
.....
}
@catch{
...
}
@finally{
...
}

Apple объясняет здесь, как создавать и обрабатывать исключения: перехват исключений

15
27.11.2008 22:23:10
я все еще
famfamfam 25.12.2019 09:03:43

Слово предостережения здесь. В Objective-C, в отличие от многих похожих языков, вы, как правило, должны стараться избегать использования исключений для общих ошибок, которые могут возникнуть при нормальной работе.

Документация Apple для Obj-C 2.0 гласит следующее: «Важно: Исключения являются ресурсоемкими в Objective-C. Вы не должны использовать исключения для общего управления потоком данных или просто для обозначения ошибок (таких как недоступный файл)»

Концептуальная документация Apple по обработке исключений объясняет то же самое, но несколькими словами: «Важно: вам следует зарезервировать использование исключений для программирования или непредвиденных ошибок во время выполнения, таких как доступ за пределы коллекции, попытки изменить неизменяемые объекты, отправить недопустимое сообщение и потеря соединения с оконным сервером. Обычно такие ошибки исправляются при создании приложения, а не во время выполнения. [.....] Вместо исключений используются объекты ошибок (NSError) и Механизм доставки ошибок какао - рекомендуемый способ сообщить об ожидаемых ошибках в приложениях Какао. "

Причины этого частично заключаются в том, чтобы придерживаться идиом программирования в Objective-C (с использованием возвращаемых значений в простых случаях и параметров путем ссылки (часто в классе NSError) в более сложных случаях), частично из-за того, что создание и отлов исключений намного дороже и И наконец (и это наиболее важно), что исключения Objective-C являются тонкой оболочкой для функций setjmp () и longjmp () в C, что существенно портит вашу осторожную обработку памяти, смотрите это объяснение .

256
7.04.2011 10:18:02
Я думаю, что это относится к большинству языков программирования: «старайтесь избегать использования исключений для распространенных ошибок». То же самое относится и к Java; плохая практика - обрабатывать ошибки пользовательского ввода (например) с исключениями. Не только из-за использования ресурсов, но и для ясности кода.
beetstra 7.12.2010 12:58:30
Что еще более важно, исключения в какао предназначены для указания на неисправимые программные ошибки. В противном случае выполняется против фреймворка и может привести к неопределенному поведению. См. Stackoverflow.com/questions/3378696/iphone-try-end-try/… для получения подробной информации.
KPM 23.01.2012 01:45:10
«То же самое относится и к Java;» Не согласен. Вы можете использовать проверенные исключения в Java просто отлично для нормальных условий ошибки. Конечно, вы не будете использовать исключения Runtime.
Daniel Ryan 1.04.2013 22:01:13
Я предпочитаю способ Какао (исключения только для ошибок программиста), поэтому я предпочел бы делать это и на Java, но реальность такова, что вы должны придерживаться типичных практик в среде, а исключения для обработки ошибок торчат как неприятный запах в Objective-C, но для этой цели в Java часто используются.
gnasher729 24.03.2014 12:46:36
Этот комментарий не отвечает на вопрос. Может быть, OP просто хочет завершить работу приложения, чтобы проверить, работает ли структура отчета о сбое должным образом.
Simon 19.03.2015 05:21:45

Что касается [NSException raise:format:]. Для тех, кто пришел из Java-фона, вы помните, что Java различает Exception и RuntimeException. Исключение является проверенным исключением, а RuntimeException не проверяется. В частности, Java предлагает использовать проверенные исключения для «нормальных условий ошибки» и непроверенные исключения для «ошибок времени выполнения, вызванных ошибкой программиста». Кажется, что исключения Objective C следует использовать в тех же местах, где вы использовали бы непроверенное исключение, а значения возврата кода ошибки или значения NSError предпочтительнее в тех местах, где вы будете использовать проверенное исключение.

33
30.12.2019 08:44:38
Да, это правильно (через 4 года: D), создайте свой собственный класс ошибок ABCError, который выходит из класса NSError, и используйте его для проверенных исключений, а не NSExceptions. Поднимите NSExceptions, где ошибки программиста (неожиданная ситуация, такая как проблема формата числа) происходят.
chathuram 15.05.2013 16:45:50

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

Например, если какая-то функция принимает значение, и это значение никогда не может быть равным нулю, тогда лучше создать исключение, чем пытаться сделать что-то «умное» ...

Риз

3
17.05.2016 19:42:42

Начиная с ObjC 2.0, исключения Objective-C больше не являются оболочкой для setjmp () longjmp () C и совместимы с исключением C ++, @try является «бесплатным», но создание и перехват исключений намного дороже.

В любом случае, утверждения (используя семейство макросов NSAssert и NSCAssert) генерируют исключение NSException, и это разумно для использования их в качестве состояний Райса.

14
6.11.2009 21:39:59
Хорошо знать! У нас есть сторонняя библиотека, которую мы не хотим модифицировать, которая генерирует исключения даже для самых маленьких ошибок. Мы должны поймать их в одном месте в приложении, и это просто заставляет нас съеживаться, но это заставляет меня чувствовать себя немного лучше.
Yuri Brigance 31.07.2014 20:35:11

Нет никаких причин не использовать исключения, как правило, в цели C, даже для обозначения исключений бизнес-правил. Apple может сказать, используйте NSError, кто заботится. Obj C существует уже давно, и когда-то ВСЯ документация C ++ говорила одно и то же. Причина, по которой не имеет значения, насколько дорого выбрасывать и перехватывать исключение, заключается в том, что время жизни исключения чрезвычайно мало и ... его ИСКЛЮЧЕНИЕ для нормального потока. Я никогда не слышал, чтобы кто-то говорил в моей жизни, что человеку, за исключением которого потребовалось много времени, чтобы его бросили и поймали.

Кроме того, есть люди, которые думают, что цель C сама по себе слишком дорога, и вместо этого код на C или C ++. Таким образом, говоря, что всегда использовать NSError плохо информирован и параноидален.

Но на вопрос этой ветки еще не ответили, какой ЛУЧШИЙ способ вызвать исключение. Способы возврата NSError очевидны.

Так ли это: [повышение NSException: ... @throw [[выделение NSException] initWithName .... или @throw [[MyCustomException ...?

Я использую проверенное / непроверенное правило здесь немного иначе, чем выше.

Важна реальная разница между (используя метафору java здесь) проверенным / непроверенным -> можно ли восстановиться после исключения. И под восстановлением я подразумеваю не просто НЕ крах.

Поэтому я использую пользовательские классы исключений с @throw для восстанавливаемых исключений, потому что, скорее всего, у меня будет какой-то метод приложения, который ищет определенные типы сбоев в нескольких блоках @catch. Например, если мое приложение представляет собой банкомат, у меня будет блок @catch для «WithdrawalRequestExceedsBalanceException».

Я использую NSException: повышение для исключений во время выполнения, так как у меня нет никакого способа восстановить это исключение, кроме как перехватить его на более высоком уровне и записать в журнал. И нет никакого смысла в создании собственного класса для этого.

В любом случае, это то, что я делаю, но если есть лучший, с таким же выразительным способом, я бы тоже хотел узнать. В моем собственном коде, так как я давно перестал кодировать C hella, я никогда не возвращаю NSError, даже если я передал его через API.

-7
28.10.2010 23:07:44
Я бы порекомендовал попытаться запрограммировать сервер с исключениями как часть обычного потока ошибок, прежде чем делать такие обобщающие утверждения, как «нет причины не использовать исключения обычно в цели C». Хотите верьте, хотите нет, но есть причины писать высокопроизводительные приложения (или, по крайней мере, части приложений) в ObjC, а создание исключений обычно серьезно снижает производительность.
jbenet 16.07.2011 01:15:31
Есть действительно очень веские причины, почему бы не использовать исключения в Какао. См. Ответ Билла Бумгарнера здесь для более подробной информации: stackoverflow.com/questions/3378696/iphone-try-end-try/… . Он знает, о чем говорит (подсказка: проверь своего работодателя). Исключения в Какао рассматриваются как неисправимые ошибки и могут приводить систему в нестабильное состояние. NSError - это способ обойти общие ошибки.
Brad Larson♦ 26.07.2011 20:49:36
Исключения являются исключительными . Несоблюдение бизнес-правил, безусловно, не подходит. «Поиск и разработка кода, исключающего исключительные ситуации, может привести к достойной победе». MSDN через codinghorror.com/blog/2004/10/…
Jonathan Watmough 12.08.2011 23:25:52
Исключения нельзя выбрасывать из блоков. Исключения, создаваемые в среде ARC, могут привести к утечке вашей программы. Таким образом, отрицательный голос.
Moszi 24.02.2012 21:47:52
«Неважно, насколько дорого выбрасывать и ловить исключение», я пишу эмулятор, в котором критична производительность. Я не могу выбросить целую кучу дорогих исключений.
NobodyNada - Reinstate Monica 8.02.2015 23:17:05

Используйте NSError для сообщения об ошибках, а не об исключениях.

Краткие сведения о NSError:

  • NSError позволяет кодам ошибок в стиле C (целым числам) четко идентифицировать основную причину и, надеюсь, позволяет обработчику ошибок устранить ошибку. Вы можете легко обернуть коды ошибок из библиотек C, таких как SQLite, в экземпляры NSError.

  • NSError также имеет то преимущество, что является объектом, и предлагает способ более подробного описания ошибки с помощью своего словарного элемента userInfo.

  • Но лучше всего то, что NSError НЕ МОЖЕТ быть выброшен, поэтому он поощряет более упреждающий подход к обработке ошибок, в отличие от других языков, которые просто бросают горячую картошку все дальше и дальше вверх по стеку вызовов, после чего об этом можно сообщить только пользователю и не обрабатываются каким-либо осмысленным образом (если вы не верите в то, что следите за самым большим принципом сокрытия информации ООП -).

Ссылка Ссылка: Ссылка

8
18.06.2013 08:38:48
Этот комментарий не отвечает на вопрос. Может быть, OP просто хочет завершить работу приложения, чтобы проверить, работает ли структура отчета о сбое должным образом.
Simon 19.03.2015 05:23:11

Вы можете использовать два метода для вызова исключения в блоке try catch

@throw[NSException exceptionWithName];

или второй метод

NSException e;
[e raise];
6
23.01.2013 11:04:28

Вот как я узнал об этом из «Руководства ранчо« Большой ботаник »(4-е издание)»:

@throw [NSException exceptionWithName:@"Something is not right exception"
                               reason:@"Can't perform this operation because of this or that"
                             userInfo:nil];
7
12.05.2014 07:33:34
Хорошо, но это не говорит о многом userInfo:nil. :)
Cœur 30.12.2019 08:46:34

Вы должны генерировать исключения только в том случае, если вы оказались в ситуации, которая указывает на ошибку программирования, и хотите остановить запуск приложения. Поэтому лучший способ генерировать исключения - использовать макросы NSAssert и NSParameterAssert и убедиться, что NS_BLOCK_ASSERTIONS не определен.

0
30.06.2014 09:01:35

Пример кода для case: @throw ([NSExceptionceptionWithName: ...

- (void)parseError:(NSError *)error
       completionBlock:(void (^)(NSString *error))completionBlock {


    NSString *resultString = [NSString new];

    @try {

    NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];

    if(!errorData.bytes) {

        @throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
    }


    NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&error];

    resultString = dictFromData[@"someKey"];
    ...


} @catch (NSException *exception) {

      NSLog( @"Caught Exception Name: %@", exception.name);
      NSLog( @"Caught Exception Reason: %@", exception.reason );

    resultString = exception.reason;

} @finally {

    completionBlock(resultString);
}

}

С помощью:

[self parseError:error completionBlock:^(NSString *error) {
            NSLog(@"%@", error);
        }];

Еще один более продвинутый вариант использования:

- (void)parseError:(NSError *)error completionBlock:(void (^)(NSString *error))completionBlock {

NSString *resultString = [NSString new];

NSException* customNilException = [NSException exceptionWithName:@"NilException"
                                                          reason:@"object is nil"
                                                        userInfo:nil];

NSException* customNotNumberException = [NSException exceptionWithName:@"NotNumberException"
                                                                reason:@"object is not a NSNumber"
                                                              userInfo:nil];

@try {

    NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];

    if(!errorData.bytes) {

        @throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
    }


    NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&error];

    NSArray * array = dictFromData[@"someArrayKey"];

    for (NSInteger i=0; i < array.count; i++) {

        id resultString = array[i];

        if (![resultString isKindOfClass:NSNumber.class]) {

            [customNotNumberException raise]; // <====== HERE is just the same as: @throw customNotNumberException;

            break;

        } else if (!resultString){

            @throw customNilException;        // <======

            break;
        }

    }

} @catch (SomeCustomException * sce) {
    // most specific type
    // handle exception ce
    //...
} @catch (CustomException * ce) {
    // most specific type
    // handle exception ce
    //...
} @catch (NSException *exception) {
    // less specific type

    // do whatever recovery is necessary at his level
    //...
    // rethrow the exception so it's handled at a higher level

    @throw (SomeCustomException * customException);

} @finally {
    // perform tasks necessary whether exception occurred or not

}

}

0
9.11.2017 11:32:31