Подтвердить что ты не робот

Каковы наилучшие методы исключения/возврата NO/nil в Objective-C?

Я новичок в Objective-C, и я вижу, что существуют различные соглашения, используемые для обработки ошибок. Есть исключения, но также есть ситуации, когда функции просто должны возвращать нуль в случае чего-то не так.

Итак, как я могу решить, когда использовать, и как обрабатывать исключения и неожиданные возвращаемые значения? Каковы наилучшие практики и красные флаги?

4b9b3361

Ответ 1

Я не буду определенно о том, что использовать, но здесь есть информация о каждом из вариантов:

Исключения

Исключения в Obj-C на самом деле не предназначены для управления потоком программы. Из документации по обработке исключений:

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

По этой причине я бы не рекомендовал использовать исключения @try/@catch только для проверки правильности работы метода.

У вас также есть несколько вариантов обработки исключений, помимо установки более высокого уровня обработчик исключенных исключений.

Ошибки

Ошибки обычно используются тремя способами:

Методы делегата

Объект может просто передать NSError своему делегату в указанный обратный вызов обработки ошибок:

- (void)myObject:(MyObject *)obj didFailWithError:(NSError *)error;

Затем делегат может принять любые соответствующие меры, в том числе, возможно, отобразить сообщение пользователю. Этот шаблон обычно используется в асинхронных API-интерфейсах на основе делегатов.

Параметры выхода

Они чаще всего используются в сочетании с логическим возвращаемым значением: если возвращаемое значение равно NO, то объект NSError можно изучить для получения дополнительной информации об ошибке.

- (BOOL)performTaskWithParameter:(id)param returningError:(out NSError **)error;

Если один из возможных шаблонов использования:

NSError *error;
if (![myObject performTaskWithParameter:@"param" returningError:&error]) {
    NSLog(@"Task failed with error: %@", error);
}

(Некоторые люди также предпочитают сохранять логический результат в переменной перед его проверкой, например BOOL success = [myObject perform...];.) Из-за линейного характера этого шаблона он лучше всего используется для синхронных задач.

Обработчики завершения на основе блоков

Довольно недавний шаблон с момента введения блоков, но весьма полезный:

- (void)performAsynchronousTaskWithCompletionHandler:(void (^)(BOOL success, NSError *error))handler;

Используется следующим образом:

[myObject performAsynchronousTaskWithCompletionHandler:^(BOOL success, NSError *error) {
    if (!success) {
        // ...
    }
}];

Это сильно варьируется: иногда вы не увидите логический параметр, просто ошибку; иногда блок обработчика не имеет аргументов, переданных ему, и вы просто проверяете свойство состояния объекта (например, это как AVAssetExportSession работает). Этот шаблон также отлично подходит для асинхронных задач, если вам нужен блок-подход.

Обработка ошибок

Cocoa в Mac OS X есть довольно тщательный путь обработки ошибок. Существует также метод удобства NSAlert + (NSAlert *)alertWithError:(NSError *)error;. В iOS класс NSError по-прежнему существует, но для обработки ошибок не существует одинаковых методов удобства. Возможно, вам придется самому сделать это самостоятельно.

Подробнее читайте Руководство по программированию ошибок.

Возврат nil

Это часто используется в сочетании с параметрами NSError out; например, метод NSData​​p >

+ (id)dataWithContentsOfFile:(NSString *)path
                     options:(NSDataReadingOptions)mask
                       error:(NSError **)errorPtr;

Если чтение файла не выполняется, этот метод возвращает nil, а дополнительная информация сохраняется в ошибке.

Одна из причин, почему это особенно удобная модель, связана с nil messaging, что можно сделать безопасно без эффекта в Obj-C. Я не буду вдаваться в подробности здесь, почему это полезно, но вы можете больше узнать об этом в другом месте в сетях. (Просто убедитесь, что нашли актуальную статью: раньше использовались методы, возвращающие значения с плавающей запятой, не обязательно возвращали 0 при отправке на нуль, но теперь они это делают, как описано в документации.)

Ответ 2

Исключения должны использоваться как можно меньше в Objective-C. Там, где другие языки будут использовать исключения, в Objective-C рекомендуется использовать объекты NSError большую часть времени.

Документация Apple по обработке исключений находится здесь: http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/Exceptions/Exceptions.html%23//apple_ref/doc/uid/10000012il

Так как же использовать объекты NSError? Что ж, если мы посмотрим на классы Apple, ошибки возвращаются с помощью указателя косвенности.

Например:

- (NSObject *)objectFromSet:(NSSet *)set error:(NSError **)error 
{
    // get an object from a set; if the set has at least 1 object 
    // we return an object, otherwise an error is returned.

    NSObject *object = [set anyObject]
    if (!object) 
    {
         *error = [NSError errorWithDomain:@"AppDomain" code:1000 userInfo:nil];
         return nil;
    }

    return object;
}

// and then we use the function like this
- (void)test
{
    NSError *error = nil;
    NSSet *set = [[[NSSet alloc] init] autorelease];
    NSObject *object = [self objectFromSet:set error:&error];
    if (object) 
    {
        // use the object, all went fine ...
    }
    else 
    {
        // handle error, perhaps show an alert view ...
    }
}

Ответ 3

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

Ответ 4

Objective-C поддерживает исключения во многом так же, как и другие языки программирования, с аналогичным синтаксисом для Java или С++. Как и в случае с NSError, исключения в Cocoa и Cocoa Touch - это объекты, представленные экземплярами класса NSException,

Вы можете использовать

 @try {
        // do something that might throw an exception
    }
    @catch (NSException *exception) {
        // deal with the exception
    }
    @finally {
        // optional block of clean-up code
        // executed whether or not an exception occurred
    }

Подробнее о обработке ошибок apple doc.