【问题标题】:NSError: Does using nil to detect Error actually turn off error reporting?NSError:使用 nil 来检测 Error 是否真的会关闭错误报告?
【发布时间】:2011-06-10 18:45:12
【问题描述】:

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

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

谢谢。

【问题讨论】:

  • nilNULLNil 之间存在差异。 nil 是实例对象,Nil 是类对象,NULL 是其他任何东西。因为&error是内存地址,不是对象,所以使用NULL

标签: objective-c null nserror


【解决方案1】:

首先,下面这行并没有什么意义:

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

【讨论】:

  • 很好地了解返回 BOOL 的方法!我完全错过了。
【解决方案2】:

传递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; 
}

引用Error Handling Programming Guide

重要提示:成功或失败由方法的返回值指示。虽然间接返回 Cocoa 错误域中的错误对象的 Cocoa 方法如果通过直接返回 nil 或 NO 指示失败,则保证返回此类对象,但在尝试对NSError 对象。


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

【讨论】:

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

不,我也是这样做的,它可以很好地检测错误。您没有将 NULL 传递给它,而是将指向 NULL 的指针传递给它,这是非常不同的事情。尽管您可能想要添加的另一个选项是。

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

【讨论】:

    猜你喜欢
    • 2013-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多