2011-12-09 7 views
5

私はこの質問をhere(とSOに関する他の質問もあります)と、Objective-Cコレクションと高速列挙に関するAppleのドキュメントを持っています。まさにここに何が起こる異なるタイプのNSArrayでの高速列挙

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

NSArrayはさまざまな種類が移入し、ループが同じように作成された場合には明らかである何をなされていませんか?ループは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として、各オブジェクトをキャストしていると信じています。それは、私は信じている上記は、私はAppleのdocumentation for Fast Enumerationにこれの正確な言及を見つけることができませんでしたが、あなたは一例でそれをチェックして、何が起こるかを見ることができます

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

に相当しています。

+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に応答するため、問題はありません。 NSNumber-lengthセレクタに応答しないため

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

、私はNSString-lengthを記録しようとすると...

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

...それはNSInvalidArgumentExceptionをスローします。短いストーリーで、Objective-Cはあなたに多くのロープを与えます。あなた自身でそれをぶら下げないでください。

+0

NSNumberがNSStringとしてキャストされていません。 NSNumberとNSStringの両方が、NSObjectの子孫です.NSObjectは、NSLogが 'description'を呼び出します。しかし、キャスティングは関係ありません。 –

+0

ああそうです。私はちょうどコード補完機能と鋳造を混同したと思います。この例を書いていたとき、 'NSNumber'のインスタンスにメッセージ' -length'についての警告は表示されませんでした。 –

+0

ああ!さて、私はあなたが何を意味していたかを見ています。 NSNumberはNSStringとして 'string'にキャストされています。私はNSLogが(記述の言及から)鋳造をしていると言っていると思っていました。私の悪い! –

3

obj-cのポインタには型情報がないことを理解しておく必要があります。 NSString*と書いても、コンパイルチェックのみです。実行時には、すべてはidです。

Obj-cランタイムは、オブジェクトが指定されたクラスであるかどうかを決して確認しません。 NSNumbersをNSStringポインタに問題なく置くことができます。オブジェクトに定義されていないメソッド(メッセージの送信)を呼び出そうとすると、エラーが表示されます。

高速列挙はどのように機能しますか?それはまったく同じです:


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

    [...] 
} 

それはより低いレベルで動作するので、ちょうど高速です。

1

isKindOfClassへのすべてのNSObjectのの応答ので、あなたはまだ最小限に鋳造を保つことができる:

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