Ответ 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; например, метод NSDatap >
+ (id)dataWithContentsOfFile:(NSString *)path
options:(NSDataReadingOptions)mask
error:(NSError **)errorPtr;
Если чтение файла не выполняется, этот метод возвращает nil
, а дополнительная информация сохраняется в ошибке.
Одна из причин, почему это особенно удобная модель, связана с nil messaging, что можно сделать безопасно без эффекта в Obj-C. Я не буду вдаваться в подробности здесь, почему это полезно, но вы можете больше узнать об этом в другом месте в сетях. (Просто убедитесь, что нашли актуальную статью: раньше использовались методы, возвращающие значения с плавающей запятой, не обязательно возвращали 0 при отправке на нуль, но теперь они это делают, как описано в документации.)