NSError:使用nil来检测错误是否真的关闭了错误报告?

7

我已经养成了这样编写错误处理代码的习惯:

 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之间没有区别,这是否意味着我实际上正在关闭它,并且永远不会收到错误消息(即使在上面的示例中删除失败)? 有更好的编码方法吗?

谢谢。


1
在编程中,nilNULLNil是有区别的。nil用于实例对象,Nil用于类对象,而NULL则用于其他任何事物。由于&error是内存地址而不是对象,因此应使用NULL - Philip007
3个回答

13
首先,以下这句话并没有太多意义:
NSDictionary *attribs = [[NSFileManager defaultManager]
 removeItemAtPath:fullPath error:&error];

-removeItemAtPath:error: 方法返回的是 BOOL 类型的值,而不是字典。

我知道你可能会对 NULL 值有疑问。但请注意,方法签名中的 error 参数有两个星号:

- (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;
}

关于返回BOOL的方法,你抓住了一个好问题!我完全没注意到。 - user557219

11

传递 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来指示失败,这些方法保证会返回此类对象,但您应该始终在尝试使用NSError对象之前检查返回值是否为nil或NO。


编辑: 如NSGod所指出,-removeItemAtPath:error: 返回 BOOL 而不是 NSDictionary *。我也已经修改了我的答案以反映这一点。

非常好的解释,非常感谢。您有一个简短的示例,调用中的检测代码可能是什么样子的吗?t 是由于 (NSError **) 错误声明,才有可能区分指向 nil 和 nil 的指针吗? - EtienneSky
@EtienneSky 我的回答展示了如何通过检查返回值来检测是否发生错误。NSGod的回答也是这样做的,但没有使用变量来存储返回值。是的,NSError **允许您区分nil对象(NSError *)和指向NSError *对象的指针(即NSError **),它可以是有效指针,或者NULL表示不需要在输出参数中存储对象。 - user557219
我认为如果方法成功返回YES(完成成功),错误对象不会被设置为非零值。你引用的苹果文档并不是这个意思。所以,检查方法的返回值和检查error是否为nil应该是等效的。 - Philip007

0

不,我用相同的方式进行操作,可以很好地检测错误。你没有将 NULL 传递给它,而是将指向 NULL 的指针传递给它,这是完全不同的事情。虽然另一个选项是你可能想要添加的。

if (error != nil){...
}else{
  [NSApp presentError:error]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接