私が行った場合:
foos[i] = [[Foo alloc] init];
foos[i].prop = @"bar";
[foos[i] baz];
...それは以下よりも効率的ではありません:
Foo *foo = [[Foo alloc] init];
foo.prop = @"bar";
[foo baz];
foos[i] = foo;
またはそれらは同等ですか?
私が行った場合:
foos[i] = [[Foo alloc] init];
foos[i].prop = @"bar";
[foos[i] baz];
...それは以下よりも効率的ではありません:
Foo *foo = [[Foo alloc] init];
foo.prop = @"bar";
[foo baz];
foos[i] = foo;
またはそれらは同等ですか?
これらは同等ではありませんが、最適化コンパイラがまったく同じバイナリコードを生成する可能性があるほど十分に近いものです。
そうでない場合でも、違いを測定するのに苦労します(foos
非常に高価なC ++クラスでない限りoperator[]
)。プロファイラーが別の言い方をするまで—このコードの最適化は時期尚早です。
配列が単純なC配列(Foo * array[11];
)の場合、パフォーマンスに大きな影響はありません。
配列がNSMutableArray
(または別の添字可能なNSタイプ)の場合、メソッドの実装を繰り返し呼び出す必要があるため(短絡ディスパッチを使用)、オーバーヘッドが発生します。一部の人はそれをマイクロ最適化と見なすでしょうが。この場合、コンパイラーは実装が何を返すかを知ることができないため、呼び出しを省略することはできません。
基本的な実時間の結果は次のとおりです。
MRC:
NSArray:27秒
Cアレイ:18秒
アーク:
NSArray:31秒
Cアレイ:18秒
およびプログラム(ARCをテストするために明らかなARC変更を実行できます):
const int NIter = 10000;
__attribute__((noinline)) void fn1() {
@autoreleasepool {
NSMutableArray * foos = [NSMutableArray array];
for (size_t idx = 0; idx < NIter; ++idx) {
NSMutableString * str = [NSMutableString new];
foos[0] = str;
[foos[0] length];
[foos removeAllObjects];
[str release];
}
}
}
__attribute__((noinline)) void fn2() {
@autoreleasepool {
NSMutableString * foos[1];
for (size_t idx = 0; idx < NIter; ++idx) {
foos[0] = [NSMutableString new];
[foos[0] length];
[foos[0] release];
foos[0] = 0;
}
}
}
int main() {
for (size_t idx = 0; idx < NIter; ++idx) {
if (UseNSArray) {
fn1();
}
else {
fn2();
}
}
return 0;
}
確かに、コンパイラがそれを最適化しない限り。効率が大幅に低下するかどうかは別の問題であり、コードが他に何をしているかによって異なります。このようなマイクロ最適化について心配することは、この付近で効率の問題の証拠がすでにない限り、一般的に無駄です。