2011-04-26 34 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仍然包含垃圾(可以是數字或字符串,或無論如何,但垃圾不多)或有效的價值。如果我們嘗試使用它,我們可能會崩潰,或者我們可能有不正確的值。

相關問題