Cocoa:为什么在方法调用之前设置'nil'?

时间:2011-04-26 01:47:26

标签: objective-c cocoa methods null

我一直在研究Apple低级文件部分Using a Directory Enumerator中的示例。

以下是代码段:

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

}

为什么localizedNameisPackageisDirectorynil方法的相关调用之前设置为getResourceValue?这只是一个过分谨慎还是需要这个?

正如getResourceValue:forKey:error:阅读the docs一样,这似乎是多余的:

  

如果值为,则返回值YES   成功填充;否则,没有。

     

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

我错过了什么吗?

5 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:1)

最好永远不要将变量保留为未定义。此外,我认为如果你这样做,你会收到一个编译器警告,如果你只修复它们,那么更容易确保没有坏警告。

答案 2 :(得分:1)

如果未将对象变量设置为nil,则其值未定义。如果您随后在未设置其值的情况下访问该变量,则您的应用程序可能会出现异常或可能发生异常或崩溃。

如果首先将值设置为nil,则不会发生这种情况。将局部对象变量初始化为nil总是很好的做法。这不适用于实例变量,因为它们始终保证始终初始化为nil。

答案 3 :(得分:1)

在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中的随机值:death。

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

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

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

答案 4 :(得分:1)

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

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

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

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