Правильная структура для проверки ошибок с помощью NSError - PullRequest
9 голосов
/ 26 июня 2009

Я кодирую различные подпрограммы и стараюсь изо всех сил держать их в чистоте и рефакторинг.

Методы, которые я создаю, начинают выглядеть примерно так:

-(IBAction)buttonPress:(id)sender {
    // Create Document Shopping List with this document
    [self doSomething:&error];

    if(error) {
        [NSApp presentError:&error];
        return nil;
    }

    [self doSomethingElse:&error];

    if(error) {
        [NSApp presentError:&error];
        return nil;
    }

    [self doYetSomethingElse:&error];

    if(error) {
        [NSApp presentError:&error];
        return nil;
    }
}

Мне нравится NSError, но это похоже на ужасно неуклюжий способ обработки всех моих ошибок.

Несколько мыслей об альтернативных способах:

a) проверка ошибок может быть встроена в методы doSomething, doSomethingElse и т. Д., Но тогда я не смогу выйти из метода нажатия кнопки, не выполнив какую-либо проверку возвращаемого значения, что привело бы меня к аналогичная структура.

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

Конечно, я упускаю что-то действительно простое здесь? Есть ли образец, который может мне помочь? Или эта структура в порядке?

Ответы [ 4 ]

11 голосов
/ 30 марта 2012

Я думаю, что ни один из ответов, представленных здесь, не учитывает рекомендуемые практики Apple.

По сути, вы никогда не должны проверять объект NSError, чтобы определить, была ли проблема. Вы проверяете, была ли проблема, проверяя значение, возвращаемое методом, который принимает указатель на указатель на NSError.

С документация Apple :

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

2 голосов
/ 26 июня 2009

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

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

Используя эту идею "распространять или обрабатывать", я бы переписал ваш пример метода следующим образом:

-(IBAction)buttonPress:(id)sender {

    // Create Document Shopping List with this document
    [self doSomething:&error];    
    if(error == nil) {
        [self doSomethingElse:&error];
        if (error == nil) {
            [self doYetSomethingElse:&error];
        }
    }

    if(error) {
        [NSApp presentError:&error];
    }    
}

Обратите внимание, что существуют веские аргументы против введения слишком большого количества вложений в конкретный метод. Такое вложение, по сути, является короткой альтернативой методам извлечения. Например, может иметь больше смысла, что «doSomething:» само вызывает doSomethingElse :, который вызывает doYetSomethingElse: например. Это наложило бы на код ту же структуру, что и if-nest, но, возможно, было бы более удобным для сопровождения.

Кроме того, я не фанат встроенных операторов возврата. В этом конкретном случае образец метода на самом деле не вызывает возвращаемое значение, но если это так, я предпочитаю устанавливать локальную переменную в возвращаемое значение и возвращать только в конце управления потоком. Выскочить из функции или метода преждевременно - верный способ встретить странные ошибки, ИМХО.

1 голос
/ 26 июня 2009

Я думаю, что реальный вопрос заключается в том, какая степень детализации вам нужна при обработке ошибок. Ваш код в основном верен, но вы можете все исправить, проверяя ошибки реже или используя универсальный подход, такой как teabot, упомянутый в его ответе с NSException. Многие встроенные функции, которые возвращают ошибки (например, moveItemAtPath :) в NSFileManager, возвращают BOOL в дополнение к предоставлению объекта NSError - так что вы также можете использовать вложенные операторы if, если вам не нужна информация NSError.

И все-таки, действительно, не очень хороший способ сделать это. Если ваш код длинный, KVO может быть отличным решением. Я никогда не пробовал это в такой ситуации.

0 голосов
/ 26 июня 2009

Примечание: Когда я опубликовал это, я не знал ни о каких дебатах об исключениях MacOS / Cocoa. Пожалуйста, имейте это в виду при рассмотрении этого ответа.

Почему бы не использовать вместо исключения ? Это позволит вам обойтись без параметра error в ваших методах и обработать ваши ошибки в одном месте.

-(IBAction)buttonPress:(id)sender {
    // Create Document Shopping List with this document
    @try {
        [self doSomething];
        [self doSomethingElse];
        [self doYetSomethingElse];
    } @catch (NSException* e) {
        [NSApp presentException:e];
    }
    return nil;
}

Вам, конечно, нужно будет генерировать исключения в соответствии с вашими методами doXXXX:

NSException* e = [NSException exceptionWithName:@"MyException"
                                         reason:@"Something bad happened"
                                       userInfo:nil];
@throw e;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...