NSError: действительно ли использование nil для обнаружения ошибки отключает сообщение об ошибке?

Я привык кодировать обработку ошибок следующим образом:

 NSError* error = nil;
 NSDictionary *attribs = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
 if (error != nil) {
  DLogErr(@"Unable to remove file: error %@, %@", error, [error userInfo]);
  return; 
 }  

Но, глядя на документацию, кажется, что я ошибся.:

- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error

При возникновении ошибки по возвращении содержит объект NSError, описывающий проблему. Передайте NULL, если вам не нужна информация об ошибке.

Технически нет разницы между nil и NULL, значит ли это, что я на самом деле отключаю это и никогда не получу сообщение об ошибке (даже если удаление в приведенном выше примере не удалось)? Есть ли лучший способ закодировать это?

Спасибо.


person EtienneSky    schedule 17.01.2011    source источник
comment
ЕСТЬ разница между nil и NULL, и Nil. nil — это объект экземпляра, Nil — объект класса, NULL — любая другая вещь. Поскольку &error — это адрес памяти, а не объект, используйте NULL   -  person Philip007    schedule 01.10.2012


Ответы (3)


Во-первых, следующая строка не имеет смысла:

NSDictionary *attribs = [[NSFileManager defaultManager]
 removeItemAtPath:fullPath error:&error];

-removeItemAtPath:error: возвращает значение BOOL, а не словарь.

Думаю, я понимаю, что вас интересует со значением NULL. Однако обратите внимание на то, что в параметре ошибки в сигнатуре метода есть 2 *:

- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error

Это означает указатель на указатель. Когда вы передаете &error, вы передаете адрес указателя на NSError. (Тьфу, кто-то другой, вероятно, может помочь мне здесь, так как моя голова все еще начинает плавать, когда я имею дело с указателями на указатели). Другими словами, даже если вы установили error в nil, вы не передаете error методу, вы передаете &error.

Итак, вот как должен выглядеть переписанный метод:

// If you want error detection:
NSError *error = nil;
if (![[NSFileManager defaultManager] removeItemAtPath:fullPath
            error:&error]) {
    NSLog(@"failed to remove item at path; error == %@", error);
    // no need to log userInfo separately
    return;
}

// If you don't:
if (![[NSFileManager defaultManager] removeItemAtPath:fullPath
            error:NULL]) {
    NSLog(@"failed to remove item at path");
    return;
}
person NSGod    schedule 18.01.2011
comment
Хороший улов о методе, возвращающем BOOL! Я полностью пропустил это. - person ; 18.01.2011

Прохождение NULL означает следующее:

BOOL itemRemoved = [[NSFileManager defaultManager] removeItemAtPath:fullPath
    error:NULL];

т. е. параметр error равен NULL. Внутри -removeItemAtPath:error: проверяет, был ли передан допустимый указатель. Если это NULL, он просто не сообщит об ошибке как экземпляр NSError, но возвращаемое значение укажет, успешно ли завершился метод.

Кроме того, ваш тест неверен. Вы не должны использовать выходной параметр error для обнаружения ошибки, потому что он может быть установлен даже если метод завершится успешно. Вместо этого вы должны использовать возвращаемое значение метода для обнаружения ошибок. Если возвращаемое значение (в данном конкретном случае) равно NO, то используйте выходной параметр error для получения информации об ошибке:

NSError *error = nil;
BOOL itemRemoved = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
if (itemRemoved == NO) {
    DLogErr(@"Unable to remove file: error %@, %@", error, [error userInfo]);
    return; 
}

Цитирование Руководства по обработке ошибок ,

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


Изменить: как указал NSGod, -removeItemAtPath:error: возвращает BOOL, а не NSDictionary *. Я отредактировал свой ответ, чтобы отразить это.

person Community    schedule 17.01.2011
comment
Отличное объяснение, большое спасибо. У вас есть короткий пример того, как может выглядеть код обнаружения в вызове? Разве не из-за объявления ошибки (NSError **) можно различать указатель на nil и nil? - person EtienneSky; 18.01.2011
comment
@EtienneSky Мой ответ показывает, как определить, произошла ли ошибка, проверив возвращаемое значение. Ответ NSGod также делает это, но без использования переменной для хранения возвращаемого значения. И да, NSError ** позволяет различать объект nil (NSError *) и указатель на объект NSError * (то есть NSError **), который может быть допустимым указателем, или NULL, чтобы указать, что нет необходимости сохранять объект в выходном параметре. . - person ; 18.01.2011
comment
Я не думаю, что для объекта ошибки будет установлено значение, отличное от нуля, если метод возвращает YES (успешное завершение). Яблочный документ, который вы цитируете, не означает этого. Таким образом, проверка возвращаемого значения метода и проверка того, является ли error нулевым, должны быть эквивалентны. - person Philip007; 01.10.2012

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

if (error != nil){...
}else{
  [NSApp presentError:error]
}
person Justin Meiners    schedule 17.01.2011