NSEnumerator
私はこれを何度も見てきましたが、ループで高速列挙を使用する方が、を使用するよりも正確に高速であるのはなぜですかnextObject:
。
3 に答える
NSEnumerator
コレクションを列挙する古い方法です。これには、列挙型を表すオブジェクトを作成し、反復ごとにそのオブジェクトのメソッドを呼び出すことが含まれます。これは何年にもわたって完全にサービス可能でしたが、ループの反復ごとに少なくとも1つのメッセージが送信されるため、それほど効率的ではありません。NSFastEnumeration
は、より現代的なアプローチであり、母国語のサポートを活用して、はるかに効率的な列挙を提供します。内部で機能する方法は、現在の列挙状態を表す構造体を作成-countByEnumeratingWithState:objects:count:
し、コレクションを繰り返し呼び出すことです。このメソッドは、objects
out-paramのオブジェクトのC配列と、count
out-param。これにより、呼び出し元はC配列を反復処理できます。本質的に、これはオブジェクトのチャンクごとに1つのメッセージ呼び出しを意味します。これは、コレクションによっては、すべてのオブジェクトを取得する単一のメッセージ呼び出しと同じくらい効率的である可能性があります。
次のようなコードが少しある場合
for (id obj in myArray) {
[obj doSomething];
}
これは、コンパイラによってほぼ同等のものに変換されます
NSFastEnumerationState __enumState = {0};
id __objects[MAX_STACKBUFF_SIZE];
NSUInteger __count;
while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
for (NSUInteger i = 0; i < __count; i++) {
id obj = __objects[i];
[obj doSomething];
}
}
使用される実際の変数は非表示であり、オブジェクトバッファーの最大サイズも実装に依存しますが、基本的な考え方はそこにあります。obj-cコレクションの反復をC配列の反復に変換します。
GNUstep libs / base / trunk / Source / NSEnumerator.m countByEnumeratingWithState:objects:count:
これはAppleの実装と同じではありませんが、理解しておくと役に立ちます。
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (id*)stackbuf
count: (NSUInteger)len
{
IMP nextObject = [self methodForSelector: @selector(nextObject)];
int i;
state->itemsPtr = stackbuf;
state->mutationsPtr = (unsigned long*)self;
for (i = 0; i < len; i++)
{
id next = nextObject(self, @selector(nextObject));
if (nil == next)
{
return i;
}
*(stackbuf+i) = next;
}
return len;
}
NSArray *array = something;
配列={{1,2}、{2,3}、{3,4}}
つまり、配列は配列の配列です。では、どのようにしてすべての配列とその値にアクセスできるのでしょうか。このようなforループを使用できます
for (int i = 0; i < array.count; i++)
{
NSArray x = [array objectAtIndex:i];
}
または高速列挙型はこのように機能します
for(NSArray array2 in array)
{
// do what ever you want with this new array2.
}
これはサンプル例です。
PS。アレイがコンソールでどのように見えるかを忘れました。