2011-04-26 63 views
1

我一直在努力通过Apple低级文件部分中的Using a Directory Enumerator中的示例。可可:为什么在方法调用之前设置'nil'?

下面的代码片段:

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被设置为nil之前,相关的呼叫到getResourceValue方法?这只是过于谨慎或者这是必需的吗?

由于the docsgetResourceValue:forKey:error:这似乎是多余的:

返回值是如果成功填充值 ;否则,否。如果 请求的资源值不 的网址定义

讨论值设为零。在这种情况下, 方法仍然返回YES。

我错过了什么吗?

回答

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

现在把一个断点test1=nil在Xcode和运行。在机,我得到:

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;再次运行它。很棒。

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

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

1

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

+0

这里没有编译器警告:'NSNumber * isDirectory,* isPackage; //其余的代码在那里......'这对我的眼睛更容易... – dawg 2011-04-26 01:58:25

5

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

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

+0

+1:这是对注释的解释'//错误检查被省略以清楚起见.'非演示代码应该检查在尝试使用间接返回的对象,'isDirectory'和错误之前,直接使用'BOOL'返回值。 – 2011-04-26 02:05:18

1

如果您未将对象变量设置为零,则其值不确定。如果随后访问该变量时未先设置其值,则应用程序可能会出现错误或可能引发异常或崩溃。

如果您将值设置为零,那么这不会发生。将局部对象变量初始化为零总是一个好习惯。这不适用于实例变量,因为它们总是被初始化为零。

1

如果检查到-getResourceValue的返回值,则它将是多余的。由于它不在上面的代码中,所以零是必要的。

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

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

正如我们不知道如果-maybeAssignAValueToPassedInPointer:没有或没有分配的值或者不是我们不知道在// 2如果aLocalVar仍然包含垃圾(可以是数字或字符串,或无论如何,但垃圾不多)或有效的价值。如果我们尝试使用它,我们可能会崩溃,或者我们可能有不正确的值。

相关问题