現代のObjective Cランタイムでのivar合成の基礎となるメカニズムは何ですか
-
07-07-2019 - |
質問
最新(64ビットOS XおよびiPhone OS)のObjective Cランタイムの機能の1つは、クラスで明示的に宣言せずにプロパティがivarを動的に合成できることです:
@interface MyClass : NSObject {
// NSString *name; unnecessary on modern runtimes
}
@property (retain) NSStrng *name;
@end
@implementation MyClass
@synthesize name;
@end
コードのかなりの部分で、プロパティを初期化するためにカスタムゲッターの実装を使用しています:
- (NSString *) name {
if (!name) {
name = @"Louis";
}
return name;
}
上記は、ヘッダーで宣言されていないivarにアクセスする必要があるため、合成されたivarとは互換性がありません。さまざまな理由で、最新のランタイムで構築されたときに合成ivarを使用するように多くの個人用フレームワークを更新したいと考えています。その目的を達成するには、合成ivarで動作するように上記のコードを変更する必要があります。
Objective C 2.0のドキュメントには、最新のランタイムで合成されたアクセサーが最初の使用時にivarを合成すると記載されています。これを行うために使用される低レベルのメカニズムを指定しません。それはclass_getInstanceVariable()によって行われますか、class_addIvar()の制限は緩められていますか、それは目的のC 2.0ランタイムで文書化されていない関数ですか?プロパティをサポートするデータ用に独自のサイドストレージを実装することはできますが、合成アクセサが使用しているメカニズムを使用したいです。
解決
先ほど行ったドキュメントをもう一度見ましたが、あなたはそれを読み間違えていると思います。合成されたivarは、実行時ではなくコンパイル時に作成されます。
ランタイムに依存する動作に違いがあります(“ランタイムの違い”も参照):
レガシーランタイムの場合、インスタンス変数は@interfaceブロックで既に宣言されている必要があります。プロパティと同じ名前で互換性のあるタイプのインスタンス変数が存在する場合、それが使用されます。そうでない場合、コンパイラエラーが発生します。
最新のランタイムでは、インスタンス変数は必要に応じて合成されます。同じ名前のインスタンス変数が既に存在する場合は、それが使用されます。
必要なのは、必要なインスタンス変数を宣言するだけです。同じコードが両方のランタイムで機能します...
他のヒント
探しているのは、次のような@synthesized nameです。
@synthesize name = _name;
...
- (NSString *) name {
if (!name) {
_name = @"Louis";
}
return _name;
}
[myObject setValue:@"whatever" forKey:@"foo"];