Каковы лучшие практики для исключений / возврата NO / nil в Objective-C? - PullRequest
22 голосов
/ 23 июля 2011

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

Ответы [ 4 ]

35 голосов
/ 23 июля 2011

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

Исключения

Исключения в 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 ). Этот шаблон также отлично подходит для асинхронных задач, когда требуется блочный подход.

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

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

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

Возвращается ноль

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

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

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

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

6 голосов
/ 23 июля 2011

Исключения должны использоваться как можно меньше в 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 (error) 
    {
        // handle error, perhaps show an alert view ...
    }
    else 
    {
        // use the object, all went fine ...
    }
}
0 голосов
/ 20 декабря 2013

Objective-C поддерживает исключения во многом так же, как и в других языках программирования, с синтаксисом, аналогичным Java или C ++. Как и в случае 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 .

0 голосов
/ 23 июля 2011

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

...