it-swarm.com.ru

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

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

407
Steph Thirion

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

[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];
520
e.James

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

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

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

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

255
harms
@throw([NSException exceptionWith…])
60
Peter Hosey

У меня нет представителя, чтобы комментировать ответ eJames, поэтому я думаю, что мне нужно поставить свой здесь. Для тех, кто происходит из Java фона, вы помните, что Java различает Exception и RuntimeException. Исключение является проверенным исключением, а RuntimeException не проверяется. В частности, Java предлагает использовать отмеченные исключения для "нормальных условий ошибки" и непроверенные исключения для "ошибок времени выполнения, вызванных ошибкой программиста". Кажется, что исключения Objective C следует использовать в тех же местах, где вы бы использовали непроверенное исключение, а значения возврата кода ошибки или значения NSError предпочтительнее в тех местах, где вы будете использовать проверенное исключение.

33
Daniel Yankowsky

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

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

Apple объясняет, как генерировать и обрабатывать исключения: Перехват исключенийБросок исключений

15
rustyshelf

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

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

14
Psycho

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

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

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

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

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

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

8
Jason Fuerstenberg

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

@throw [NSException exceptionWithName:@"Something is not right exception"
                               reason:@"Can't perform this operation because of this or that"
                             userInfo:nil];
7
Johannes

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

@throw[NSException exceptionWithName];

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

NSException e;
[e raise];
6
Subbu

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

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

Риз

3
R. van Twisk

Пример кода для 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
Aleksandr B.

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

0
gnasher729