2011-12-09 96 views
5

我有這樣的疑問here(以及上的其他quesrtions),以及約Objective-C的集合和快速列舉了蘋果文檔。什麼是不明確的,如果填充了不同類型的NSArray和循環就好創建:快速計數

for (NSString *string in myArray) 
    NSLog(@"%@\n", string); 

到底會發生什麼嗎?循環會跳過什麼不是NSString?例如,如果(出於參數的原因)UIView在數組中,當循環遇到該項目時會發生什麼?

+3

快速列舉「需要你的話。」 @awfullyjohn提供了處理具有未知類成員的數組的最佳解決方案。沒有隱式的過濾發生,並可能導致調用接收器無法處理的方法...崩潰 –

回答

9

爲什麼要這麼做?我認爲這會造成越野車和意外行爲。如果陣列中填充了不同的元素,而不是使用:

for (id object in myArray) { 
    // Check what kind of class it is 
    if ([object isKindOfClass:[UIView class]]) { 
     // Do something 
    } 
    else { 
     // Handle accordingly 
    } 
} 

你在做什麼在你的例子是有效的一樣,

for (id object in myArray) { 
    NSString *string = (NSString *)object; 
    NSLog(@"%@\n", string); 
} 

僅僅因爲你投object作爲(NSString *)不意思是string實際上將指向NSString對象。以這種方式調用NSLog()將根據NSObject protocol調用- (NSString *)description方法,其中在數組內引用的類可能符合或不符合。如果它符合,它會打印。否則,它會崩潰。

+1

好的一點,但這不能回答這個問題。 – PengOne

+0

問題是對Objective-C的更深入的理解,而不是實際做這樣的事情。另外,最近我一直在C#中工作,可以指定進入集合的類型。 –

+1

是的。我會更新我的答案,但基本上,你擊敗了我。 – john

2

有趣的問題。爲快速列舉最通用的語法是

for (NSObject *obj in myArray) 
    NSLog(@"%@\n", obj); 

我相信,通過做

for (NSString *string in myArray) 
    NSLog(@"%@\n", string); 

相反,你只是鑄造每個對象爲NSString。也就是說,我認爲上述等同於

for (NSObject *obj in myArray) { 
    NSString *string = obj; 
    NSLog(@"%@\n", string); 
} 

我找不到在蘋果的documentation for Fast Enumeration的這種精確提,但你可以檢查它的例子,看看會發生什麼。

+1

不是「最通用」版本是「for(id obj in arr)」(因爲覆蓋了(微小的數字)不從'NSObject'下降的對象)? –

2

我只是試過一個簡單的例子...這是我的代碼。

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1]; 
NSNumber *number = [NSNumber numberWithInteger:6]; 
[array addObject:number]; 
[array addObject:@"Second"]; 

現在,如果我只是登錄對象,沒有問題。 NSNumber實例正在鑄造爲NSString,但兩種方法都響應-description,所以它不是問題。

for (NSString *string in array) 
{ 
    NSLog(@"%@", string); 
} 

但是,如果我嘗試登錄NSString-length ...

for (NSString *string in array) 
{ 
    NSLog(@"%i", string.length); 
} 

...它拋出一個NSInvalidArgumentException因爲NSNumber不向-length選擇作出迴應。長話短說,Objective-C給你很多繩索。不要把它掛在上面。

+0

NSNumber不作爲NSString被轉換。 NSNumber和NSString都是NSObject的後代,NSLog就像你說的那樣調用'description'。但沒有涉及任何投射。 – 2011-12-09 23:33:47

+0

哦,我明白了。我想我只是混淆了鑄造和代碼完成功能。在我寫這個例子的時候,我沒有收到關於'NSNumber'實例的消息'-length'的警告。 –

+0

啊!好的...我現在也明白你的意思了。 NSNumber被作爲一個NSString轉換爲'string'。我以爲你是在說NSLog正在做鑄造(從提及'description')。我的錯! – 2011-12-09 23:56:58

3

你要明白,在OBJ-C的指針沒有類型信息。即使您編寫NSString*,也只是一個編譯檢查。在運行期間,一切都只是一個id

Obj-c運行時從不檢查對象是否是給定的類。您可以將NSNumbers放入NSString指針中而不會出現問題。只有當您嘗試調用未在對象上定義的方法(發送消息)時纔會出現錯誤。

快速枚舉如何工作?它完全一樣:


for (NSUInteger i = 0; i < myArray.count; i++) { 
    NSString* string = [myArray objectAtIndex:i]; 

    [...] 
} 

這只是因爲它在較低的水平上運行更快。

1

由於所有的NSObject對isKindOfClass迴應,你仍然可以鑄造保持在最低限度:在類

for(NSString *string in myArray) { 
    if (![string isKindOfClass:[NSString class]]) 
     continue; 
    // proceed, knowing you have a valid NSString * 
    // ... 
}