7

私は宣言しています:

static NSString *a = @"a";

これは iOS6 での正しい宣言です (コンパイラ バージョンを使用する方が正しいはずですが、現時点ではわかりません)。数値リテラルでも次のように考えました。

static NSNumber *b=@1;

有効な宣言である可能性があります。コンパイラはそれを教えてくれinitializer element is not a compile time constantます。これには少し驚かされます。NSNumberは不変であり、文字列の場合のようにリテラルを使用しているためNSString、それも有効であると考えました。

誰もこの違いについて合理的な説明を持っていますか?

4

1 に答える 1

21

最初の行は、割り当てているのでコンパイル時定数であり、@"a"次のようなものではありませんstatic NSString *a = [NSString stringWithFormat:@"a"];(同じエラーがスローされます)

ただし、の場合NSNumberstatic NSNumber *b = @1;実際には。と同等static NSNumber *b = [NSNumber numberWithInt:1];です。詳細については、Objective-Cリテラルを確認してください。

上記の場合、右側はコンパイル時定数ではないことに注意してください。これは、実行時に評価する必要がある式です。CおよびObjective-Cでは、静的変数はコンパイル時の定数で初期化する必要があります。

NSNumberとして使用したい場合はconst、ここで説明したアプローチで確認できます。ObjectiveC-外部変数の使用方法は?

MikeAshのObjectiveCリテラルでもこれを確認してください。

新しいリテラル構文はいずれもコンパイル時定数として適格ではないことに注意することが重要です。

と、

NSStringリテラルは、コンパイラとライブラリが緊密に結合されているため、コンパイル時定数でもあります。固定されたivarレイアウトを持つNSConstantStringと呼ばれる特別なNSStringサブクラスがあります。

この密結合には、有効なグローバル変数初期化子を生成したり、実行時にオブジェクトをビルドするために追加のコードを実行する必要がないなどの利点があります。ただし、大きな欠点もあります。NSConstantStringレイアウトは永久に設定されます。そのデータレイアウトは何千ものサードパーティアプリに組み込まれているため、そのクラスは正確にそのデータレイアウトで維持する必要があります。Appleがレイアウトを変更した場合、それらのサードパーティ製アプリは古いレイアウトのNSConstantStringオブジェクトを含んでいるため、壊れてしまいます。

NSArrayリテラルがコンパイル時定数である場合、コンパイラが生成できる固定レイアウトの同様のNSConstantArrayクラスが必要であり、他のNSArray実装とは別に維持する必要があります。このようなコードは、このNSConstantArrayクラスを持たない古いOSでは実行できませんでした。新しいリテラルが生成できる他のクラスにも同じ問題が存在します。

これは、NSNumberリテラルの場合に特に興味深いものです。Lionはタグ付きポインターを導入しました。これにより、NSNumberのコンテンツをポインターに直接埋め込むことができるため、動的に割り当てられた個別のオブジェクトが不要になります。コンパイラがタグ付きポインタを発行した場合、それらの形式は変更できず、古いOSリリースとの互換性が失われます。コンパイラが定数NSNumberオブジェクトを発行した場合、NSNumberリテラルは他のNSNumberとは大幅に異なり、パフォーマンスが大幅に低下する可能性があります。

代わりに、コンパイラはフレームワークに呼び出しを発行するだけで、手動で行ったのとまったく同じようにオブジェクトを構築します。これにより、実行時のヒットが少し発生しますが、新しい構文を使用せずに自分でビルドするよりも悪くはなく、はるかにクリーンな設計になります。

于 2012-12-14T02:03:16.753 に答える