4

列挙がどのように高速に機能するかの詳細を完全には理解していませんが、次の 2 つのケースを比較してください。

for(NSObject *object in self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array) {
    // do something
}

対。

NSArray *array = self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array;
for(NSObject *object in array) {
     // do something
 }

最初の例では、反復ごとにそのチェーン全体を通過して配列を取得しますか? 2番目の方法を使用する必要がありますか?

4

2 に答える 2

7

AppleがFastEnumerationを導入したとき、私はWWDCにいましたが、(思い出しますが)右側のオブジェクトが一時的に移動すると言われました。さらに、これが機能するためである必要があります。

for(id foo in [myCollection reverseObjectEnumerator])

高速列挙を実行するコレクションは、次の1つのメソッドを持つ「高速列挙プロトコル」(NSFastEnumeration)を採用していることがわかります。

– countByEnumeratingWithState:objects:count:

このメソッドは、オブジェクトのC配列を返します。これにより、列挙が非常に高速になり、右側の1回限りの使用がサポートされます。


さて、そうは言っても、現在Appleは開発者(WWDC)にブロック列挙を使用するようにアドバイスしています。ブロック列挙はより高速で、生成されるコードも少ないと彼らは主張しています。

[myCollection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
... your code
} ];

私が好きなのは「idobj」ではなく、実際のタイプ(ブロックでのキャストを避けるため)です。

[myCollection enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop)
{
... your code
} ];

これを行っても、コンパイラーもアナライザー(4.4)も文句を言いません。

このメソッドの外部で変数を設定する必要がある場合は、それをブロック変数にする必要があります。

__block int foo = 0;
[myCollection enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop)
{
   foo = MAX(foo, [num integerValue]);
} ];

編集:明確にするために、あなたの質問への直接の答えは「いいえ」であり、ステートメント「self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array」は一度評価され、最後のオブジェクトは一時としてスタックに保存されます。また、ブロック列挙でも同じ手法を使用できます。ステートメントが1回評価され、最後に返されたオブジェクトが列挙に使用されます。

__block int foo = 0;
[self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop)
{
   foo = MAX(foo, [num integerValue]);
} ];

EDIT2:この同じトピックが議論されたSOで別のスレッドを見つけました。ブロック列挙に関して私が見逃した1つのポイントは、少し複雑な方法を使用して、ブロックを同時に(または逆に)実行するように指定できることです。

enumerateObjectsWithOptions:usingBlock:

iOSデバイスがますます多くのコアを取得するにつれて、これはあなたが何をしているかによっては大きな勝利になる可能性があります。

質問に対する@bbumの応答(および他の人も)はここにあります。

于 2012-09-05T13:16:06.333 に答える
3

これはおそらくコンパイラ固有 (未定義) です。気になる場合は、タイミングコードを追加して、自分で調べてください。

#import <sys/time.h>

static unsigned getTickCount()
{
    struct timeval tv;
    gettimeofday(&tv, 0);
    return (unsigned)((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
}

...

unsigned startTime = getTickCount();
for(NSObject *object in self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array) {
    // do something
}
unsigned endTime = getTickCount();
NSLog(@"That took %umS", endTime - startTime);

ただし、上記のものを登録するには、かなり大きな配列が必要0です。

于 2012-09-05T12:40:04.810 に答える