Objective-C オブジェクトは、ヒープに割り当てられる単なる C 構造体です (多かれ少なかれ)。インスタンス変数 (ivar) を宣言すると、その構造体へのオフセットとして定義されます。したがって、次のような ivars を手動で宣言した場合 (もうこのようにしないでください。ただし、要点を示しています):
@interface Foo : NSObject {
NSString *ivar1;
NSString *ivar2;
}
次に+alloc、新しいインスタンスを呼び出すと(それを呼び出すfoo)、構造体はヘッダーになり、その後に NSObject の ivar が続き、その後に memory forivar1が続き、その後に memory for が続きますivar2。ポイントにいくらかのオフセットを加えたものivar1になります。foo(これはもはや正確ではありませんが、私と一緒にいてください。古い実装を理解する方が簡単です。)
は構造体へのポインタであるためfoo、実際にはこのオフセット ポインタを として直接参照できますfoo->ivar1。それは本当に構造体です。これは絶対に行わないでください。ただし、これは正当な構文です。
@implementationブロック内では、ivar1自動的に に変換されself->ivar1ます。がどのように実装されているかについてあまり心配する必要はありませんselfが、それが構造体へのポインターであることを信頼してください。繰り返しますが、この->構文は絶対に使用しないでください。これは基本的な実装の詳細です (そして、常に可能であるとは限りません。以下を参照してください)。
OK、それが ivar です。昔 (ObjC 1.0) では、実際にはそれしかありませんでした。ivar を宣言し、値を設定して返すアクセサー メソッドを手動で作成しました。
その後、ObjC2 が登場し、場合によっては、壊れにくい ABI と呼ばれるものも提供されました。これにより、ivar の基本的な実装が多少変更されるため、常に実際に使用できるとは限り->ません。しかし、とにかくそれを使用していないはずです。とはいえ、昔ながらのふりをする方が簡単です。さらに重要なことに、ObjC2 は「プロパティ」と呼ばれるこの新しいものを追加しました。プロパティは、特定のメソッドを実装するという単なる約束です。だからあなたが言うとき:
@property (nonatomic, readwrite, strong) NSString *property;
これは、次のように言うのとほぼ同じです。
- (NSString *)property;
- (void)setProperty:(NSString *)aProperty;
(違いが重要になることはめったにありません。) これは実装を提供しないことに注意してください。それはivarを作成しません。いくつかのメソッドを宣言するだけです。
ObjC1 では、同じアクセサー コードを何度も何度も書きました。20 個の書き込み可能な ivar があり、40 個のアクセサー メソッドを記述しました。そして、それらはほとんど同じでした。ムカつく機会が多い。そして、多くの退屈。Accessorizerに感謝します。
ObjC2 では、 を追加すると、コンパイラは最も一般的な実装を無料で提供します@synthesize。プロパティと同じ名前の ivar を自動的に作成し、その ivar を読み書きするための getter と (必要に応じて) setter を書き込みます。渡す=_propertyと、使用される ivar の名前が変更されるだけです。これを「バッキング ivar」と呼びます。
現在、コンパイラの最新バージョンでは、@synthesize. このパターンは非常に一般的であり、何十年も続いているため、コンパイラに実行しないように指示しない限り、現在ではデフォルトになっています。また、先頭にアンダースコアが付いた ivar を自動的に合成します (これがベスト プラクティスです)。
知っておくべきもう 1 つの情報は、オブジェクト内であっても、ivar にアクセスするには常にアクセサーを使用する必要があるということです。唯一の例外はメソッドinitとdeallocメソッドです。そこで、ivar に直接アクセスする必要があります (先頭のアンダースコアを使用)。