2012-08-01 132 views
4

我剛剛發現了一些令我有點困惑的東西,不知有人會爲我澄清這件事。ID沒有警告?

NSArray *nextArray = [NSArray arrayWithObjects:@"ONE", @"TWO", @"THREE", nil]; 
for(id eachObject in nextArray) { 
    NSLog(@"COUNT: %d", [eachObject length]); 
} 

爲什麼上述內容不會抱怨/警告我正在詢問身份證的長度這一事實?

+0

因爲(id)可能是任何NSObject。就像一個可以有長度的NSString。 – Popeye 2012-08-01 16:53:23

+1

@Popeye:甚至不需要是NSObject。可以繼承NSProxy,或者一些完全不同的基類。儘管在實踐中,幾乎所有東西都至少符合NSObject協議。 – 2012-08-01 16:59:15

+0

我看到了,我知道id可以是任何Objective-C類,但我一直認爲你必須在嘗試訪問它之前檢查類型並進行投射。非常感激。 – fuzzygoat 2012-08-01 17:00:20

回答

4

當您不需要編譯器類型檢查時,您可以使用id。您可以發送任何消息到id類型而不發出警告,並且您可以將id分配給任何其他類型,而不進行類型轉換。

這允許您從數組中取出一個對象而不使用轉換。例如,你可以自由地假設數組包含NSString的:

NSString* someString = [myArray objectAtIndex:1]; 

它也可以讓你將消息發送到一個對象而澆注或者警告。實際上,您希望發送的消息可能不是任何正式類別或協議的一部分:

id someObject = [myArray objectAtIndex:1]; 
if ([someObject respondsToSelector:@selector(setName:)]) 
{ 
    [someObject setName:@"Foo"]; 
} 
4

編譯器永遠不會輸入發送給ID的檢查消息。這部分是Objective-C的活力所在。

如果eachObject是任何其他類型,那麼如果編譯器無法解析方法名稱,則會發生錯誤。

0

Objective-C中的每個對象都知道它有什麼類,它是否可以處理消息。編譯器不是檢查類,它是運行時的對象本身。

對象的類可以在compilertime時未定義,但是在運行時每個對象都有一個定義的類。

1

簡單地說,id表示所有的Objective-C類。所以,它的長度方法它屬於一個NSString類。編譯器不會向您發出警告。 id在運行時動態確定,在編譯時未知。

5

In Objective-C id是任何類型對象的普通類型,不管類是什麼類型的,都可以用於類的實例和類對象本身。 id類型完全是非限制性它沒有關於對象的信息,除了它是一個對象。所以編譯器無法知道該對象是否可以響應某個方法,因爲它不知道它是什麼類型的對象。 通過在你的代碼中使用它,你基本上會說'不管這是指向什麼,執行這個操作'。

3

NSArray可能包含不同的對象類型,例如:

NSArray *thArray = [[NSArray alloc] initWithObjects:@"Stack",@"Overflow",[NSNumber numberWithInt:10],nil]; 
for(id theObject in thArray) { 
    NSLog(@"COUNT: %lu", [theObject length]); 
} 

id可以表示任何對象(在此情況下NSStringNSNumber),
爲此編譯器不能知道原始的方法length是否存在。

+0

優秀的答案,但你可能想糾正一件小事:'長度'不是一個屬性。 – jlehr 2012-08-01 17:01:00

+0

哎呀,愚蠢的錯誤,用'原始方法'取代'property'。謝謝:) – Anne 2012-08-01 17:03:57

+1

謝謝,它可能值得添加如果([theObjectresponseToSelector:@selector(length)]){...以防萬一有人認爲代碼將在運行時工作。 – fuzzygoat 2012-08-01 17:25:16