Определение метода, который возвращает ошибку

Как определить метод, который возвращает ошибку, а также значение?

Например, когда я вызываю сохраненный метод managedObjectContext, метод возвращает логическое значение вместе с ошибкой:

if(![context save:&error]) {
    NSLog(@"%@", error);
}

Не могли бы вы дать мне прямой пример определения метода, стоящего за этим?

Редактирование / обновление: с той же точки зрения, как было бы возможно передать несколько ошибок. Я делаю что-то не так (я, вероятно, еще не понимаю концепцию), которая не работает:

NSArray *errors = nil;
[self throwMultipleErrors:&errors];
for(id error in errors) {
    NSLog(@"Muliple error: %@", error);
}...

-(BOOL)throwMultipleErrors:(NSMutableArray **) errors {
    [*errors addObject:@"First Error"];
    [*errors addObject:@"Second Error"];
    [*errors addObject:@"Third Error"];

    return YES;
}

3 ответа

Решение

В вашем примере подпись метода:

- (BOOL)save:(NSError **)error;

Это позволяет вызывающей стороне передать в NSError как адрес, а не указатель (указатель на указатель, ** а также &), что метод затем может быть назначен из другой области. И если метод возвращает false, вызывающая сторона может затем проверить содержимое переменной error, как показано в вашем примере.

Смотрите этот вопрос для получения дополнительной информации об использовании & перед переменными и (NSError **) подписи.

Почему `&` (амперсанд) ставится перед некоторыми параметрами метода?

Пример реализации:

    - (BOOL)save:(NSError **)error
    {
       NSAssert(error != nil, @"Passed NSError must be nil!");
       // Attempt to do a save
       if (saveDidFail) {
             NSDictionary *userInfo = [NSDictionary dictionaryWithObjectAndKeys:@"Save Failed", kCustomErrorKey, nil];
             *error = [NSError errorWithDomain:@"domain" code:999 userInfo:userInfo];
             return NO;
       } 
       return YES;
    }

Используя ваш пример, подпись метода будет:

-(BOOL)save:(NSError**)error;

Теперь, когда вы используете двойные указатели, вы должны быть осторожны в программировании. Во-первых, вы должны убедиться, что значение error не является nil, затем *error является nil, Вы должны сделать это, потому что вы не знаете, что делать с памятью для существующего объекта. Например:

NSError *error = nil;
[self save:&error];

было бы правильно. Но

NSError *error = [[NSError alloc] init];
[self save:&error];

это проблема, потому что ваш save: метод не будет, если error является retained или же autoreleased, если ты release это и это autoreleased тогда ваше приложение в конечном итоге рухнет. И наоборот, если вы этого не сделаете release это и есть retained вы теряете память. Я рекомендую проверить это с помощью assert, чтобы проблема была быстро устранена, прежде чем код будет зарегистрирован.

NSAssert(!error || !*error, @"*error must be nil!");

Наконец, при настройке *error Вы должны убедиться, что error не является nil, Вам никогда не разрешается устанавливать значение адреса памяти 0x0, Если вы не проверяете и если вы проходите nil в методе вы потерпите крах, если попытаетесь установить его.

if (error)
{
    *error = [NSError ...];
    return NO;
}

Чтобы вернуть массив, я бы сделал что-то вроде этого:

-(BOOL)throwMultipleErrors:(NSError **) error {

    NSAssert(!error | !*error, @"*error must be nil");

    NSMutableArray *errorList = nil;

    if (error)
        errorList = [NSMutableArray array];


    [errorList addObject:@"First Error"];
    [errorList addObject:@"Second Error"];
    [errorList addObject:@"Third Error"];

    if (error && [errorList count] > 0)
    {
        *error = [NSError errorWithDomain:@"Some error"
                                     code:0
                                 userInfo:@{@"suberrors" : [NSArray arrayWithArray:errorList]}];
        return NO;
    }

    return YES;
}

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

Заметки

Конечно, вы бы на самом деле бросили [self save:&error]; позвонить в if() заявление для проверки возвращаемого значения. Заметьте, однако, что мы проходим в &error а не просто error, Это потому, что нам нужно передать указатель на errorне error сам. &error читается как "Адрес ошибки".

Мы должны быть осторожны с синтаксисом здесь. Когда мы передаем NSError в метод: + (instancetype)stringWithContentsOfFile:(NSString *) кодировка пути:(NSStringEncoding)enc error:(NSError * *)error

мы передаем дескриптор (указатель на указатель) на объект ошибки, который еще не был инициализирован. Если вызываемое сообщение сталкивается с проблемой, оно инициализирует и заполняет объект ошибки. Он не "вернет" ошибку, просто заполните значения переданным параметром.

поэтому, если я хочу определить сообщение, которое возвращает значение, а также принимает параметр ошибки, следуйте этому руководству: http://www.cimgf.com/2008/04/04/cocoa-tutorial-using-nserror-to-great-effect/

Другие вопросы по тегам