【问题标题】:Cocoa: Why set 'nil' prior to the method call?Cocoa:为什么在方法调用之前设置'nil'?
【发布时间】:2011-08-12 16:58:05
【问题描述】:

我一直在研究 Apple Low-Level File 部分中Using a Directory Enumerator 中的示例。

这是一个代码sn-p:

for (NSURL *url in enumerator) {

// Error-checking is omitted for clarity.

NSNumber *isDirectory = nil;
[url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL];

if ([isDirectory boolValue]) {

    NSString *localizedName = nil;
    [url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL];

    NSNumber *isPackage = nil;
    [url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:NULL];

    if ([isPackage boolValue]) {
        NSLog(@"Package at %@", localizedName);
    }
    else {
        NSLog(@"Directory at %@", localizedName);
    }
}

}

为什么localizedNameisPackageisDirectory 在对getResourceValue 方法的相关调用之前设置为nil?这只是过于谨慎还是需要这样做?

the docs阅读getResourceValue:forKey:error:似乎是多余的:

返回值 YES 如果值是 成功填充;否则,否。

讨论值设置为零,如果 请求的资源值不是 为 URL 定义。在这种情况下, 方法仍然返回 YES。

我错过了什么吗?

【问题讨论】:

    标签: objective-c cocoa methods null


    【解决方案1】:

    此代码不检查getResourceValue:forKey:error: 方法是否实际成功。相反,它假设当方法失败时,传递的变量要么设置为 nil,要么保持不变。这可能不是一个有根据的假设;似乎没有记录失败的行为。

    如果它们没有事先初始化,“保持不变”会通过使用未初始化的堆栈变量导致未定义的行为。

    【讨论】:

    • +1:这是注释 // Error-checking is omitted for clarity. 的解释,非演示代码应在尝试使用任何间接返回的对象 isDirectory 和错误。
    【解决方案2】:

    在 C NULL 指针类型的东西下归档这个。

    这是一个例子:

    #import <Foundation/Foundation.h>
    
    void test(void){
        NSString *test1, *test2, *test3;
    
        test1=nil;
        // Note: NSString would USUALLY be aloc then init before use...
        [test1 isEqual:@"static object string"];
        [test2 isEqual:@"static string"];
        [test3 isEqual:test1];
    
    }
    
    int main (int argc, const char * argv[])
    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        test();
    
        [pool drain];
        return 0;
    }
    

    现在在 xcode 中的 test1=nil 上放置一个断点并运行。在我的机器上,我得到:

    test1=(NSString *) 0x0 <nil>
    test2=(NSString *) 0x0 <nil>
    test3=(NSString *) 0x7fff84db7dd7 Invalid
    

    如果你运行它,你会得到EXC_BAD_ACCESS,并在它尝试执行[test3 isEqual:test1]时终止。您可以使用 test1 的 nil 值和(意外?) test2 的 nil 值,但使用 test3 中的随机值:死亡。

    现在将该行更改为test1=test2=test3=nil; 再次运行它。效果很好。

    一个重要的概念:Objective-C 中的You can validly send a message to nil

    就像在不使用时将 C 指针分配给安全值可能是一种好习惯一样,nil 在 Objective-C 中是一个安全值,直到它被分配给其他东西。对于编写示例的程序员来说——这可能是肌肉记忆。在特定情况下是不必要的,但比随机值更安全。

    【讨论】:

      【解决方案3】:

      永远不要让变量未定义是个好习惯。另外,我认为如果你这样做了,你会得到一个编译器警告,如果你只是修复它们,更容易确保你没有错误的警告。

      【讨论】:

      • 没有编译器警告:NSNumber *isDirectory, *isPackage; // rest of the code there...,这在我看来更容易......
      【解决方案4】:

      如果您不将对象变量设置为 nil,则其值未定义。如果您随后访问该变量而没有先设置它的值,您的应用程序可能会出现异常或可能引发异常或崩溃。

      如果您先将值设置为 nil,则不会发生这种情况。将局部对象变量初始化为 nil 始终是一个好习惯。这不适用于实例变量,因为它们保证总是被初始化为 nil。

      【讨论】:

        【解决方案5】:

        如果检查了 -getResourceValue 的返回值,那将是多余的。因为它不在上面的代码中,所以 nil 是必要的。

        id aLocalVar;
        // 1
        [ob maybeAssignAValueToPassedInPointer:&aLocalVar];
        // 2
        

        在上面的代码中,//1 aLocalVar 指向内存中的随机垃圾位 - 可以是任何东西。

        由于我们不知道 -maybeAssignAValueToPassedInPointer: 是否分配了值,我们在 //2 不知道 aLocalVar 是否仍然包含垃圾(可能是一个数字,或一个字符串,或其他任何东西,但垃圾不少)或一个有效值。如果我们尝试使用它,我们可能会崩溃,或者我们的值可能不正确。

        【讨论】:

          猜你喜欢
          • 2012-09-07
          • 2014-01-12
          • 1970-01-01
          • 1970-01-01
          • 2015-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多