宣言されたプロパティには対応するインスタンス変数が必要ですか?


101

Objective-C 2.0のプロパティでは、対応するインスタンス変数を宣言する必要がありますか?たとえば、私は次のようなことに慣れています:

MyObject.h

@interface MyObject : NSObject {
NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end

MyObject.m

@implementation
@synthesize name;
@end

ただし、代わりにこれを実行した場合:

MyObject.h

@interface MyObject : NSObject {
}
@property (nonatomic, retain) NSString *name;
@end

これはまだ有効ですか?そして、それは私の前の例と何らかの点で異なりますか?


2番目の「MyObject.h」が「MyObject.m」ではなく太字になっているのはなぜですか?
Ríomhaire

回答:


93

Modern Objective-Cランタイム(iOS 3.x以降、または64ビットSnow Leopard以降)を使用している場合は、このような場合にプロパティのivarを定義する必要ありませ

いつ@synthesizeプロパティは、IVARが実際にあなたのためにも合成されます。これは「壊れやすいivar」シナリオを回避します。あなたはココアで愛についてそれについてもっと読むことができます


71

インターフェースでは、中括弧の間、中括弧の@property外、またはその両方を介して、インスタンス変数を正式に宣言できます。どちらにしても、それらはクラスの属性になります。違いは、を宣言すると@property@synthesizegetter / setterを自動コーディングするusingを実装できることです。たとえば、オートコーダーセッターは整数と浮動小数点をゼロに初期化します。インスタンス変数を宣言し、対応するを指定し@propertyない場合@synthesize、使用できず、独自のゲッター/セッターを作成する必要があります。

独自に指定することで、自動コード化されたゲッター/セッターをいつでもオーバーライドできます。これは通常、managedObjectContext遅延読み込みされるプロパティで行われます。したがって、あなたmanagedObjectContextはプロパティとして宣言しますが、その後、-(NSManagedObjectContext *)managedObjectContextメソッドも書きます。インスタンス変数/プロパティと同じ名前を持つメソッドが「getter」メソッドであることを思い出してください。

@property宣言方法はまた、あなたのような他の選択肢、可能にretainし、readonlyインスタンス変数の宣言方法にはありません、。基本的にivarは、古い方法であり、それを@property拡張して、より洗練された/より簡単なものにします。どちらでも自己参照できます。名前がそのクラスに一意である限り、プレフィックスかどうかは関係ありません。そうでない場合、スーパークラスがあなたと同じプロパティ名を持っている場合、自分が話している名前を指定するために、self.nameまたはsuper.nameのように言う必要があります。

したがって、ivar中括弧の間にsを宣言する人が少なくなり、代わりにを指定@propertyしてからを実行するようになり@synthesizeます。対応するがない@synthesizeと、実装で行うことはできません@property。Synthesizerは、@property仕様からそれがどのタイプの属性であるかを知るだけです。合成ステートメントでは、プロパティの名前を変更することもできるため、コード内で1つの名前(省略形)を使用してプロパティを参照できますが、.hファイルの外部では完全な名前を使用できます。ただし、XCodeが持つ非常に優れたオートコンプリートを使用すると、これはそれほど有利ではありませんが、依然として存在します。

これがあちこちに浮かんでいるすべての混乱と誤った情報を取り除くのに役立つことを願っています。


今では@synthesizeを書く必要はありません。その場合、この答えはどのように有効ですか?
raaz 2013年

<code> @property ... @ synthesize </ code>を宣言する必要はありません。合成を使用すると、実装でゲッター/セッターを作成する必要がなくなります。合成しない場合は、独自のゲッター/セッターをロールする必要があります
PapaSmurf 2013年

2
@PapaSmurf不正解です。あなたは使うことができます@property、そしてない使用し@synthesize、それらを自分で実装していません。コンパイラーは自動的synthesizeに作成するので、これ以上書く必要はありません。
jbrennan 2013年

8

どちらの方法でも機能しますが、中括弧で宣言しないと、xcodeのデバッガーでそれらの値が表示されません。


3

ドキュメントから:

一般に、プロパティの動作は、モダンランタイムとレガシーランタイムの両方で同じです(Objective-Cランタイムプログラミングガイドの「ランタイムバージョンとプラットフォーム」を参照)。重要な違いが1つあります。モダンランタイムはインスタンス変数の合成をサポートしていますが、レガシーランタイムはサポートしていません。

@synthesizeをレガシーランタイムで機能させるには、プロパティの同じ名前と互換性のあるタイプのインスタンス変数を提供するか、@ synthesizeステートメントで別の既存のインスタンス変数を指定する必要があります。最新のランタイムでは、インスタンス変数を指定しない場合、コンパイラーがインスタンス変数を追加します。


3

XCode 4.4以降を使用している場合は、インスタンス変数合成コードが生成されます。

以下のようにプロパティを宣言する必要があります。合成コードとインスタンス変数宣言コードが生成されます。

@property (nonatomic, strong) NSString *name;

それはとして合成コードを生成します

@synthesize name = _name;

_nameを使用してインスタンス変数にアクセスできます。これは宣言と同様です

NSString* _name

ただし、読み取り専用プロパティを次のように宣言した場合

@property (nonatomic, strong, readonly) NSString *name;

コードを生成します

@synthesize name;

または

@synthesize name = name; 

したがって、独自の合成コードを記述できる方法で接頭辞「_」を付けずにインスタント変数名にアクセスする必要があります。そうすると、コンパイラがコードを生成します。あなたは書ける

@synthesize name = _name;

1

Objective-Cプログラミング言語:プロパティ実装ディレクティブ

ランタイムに依存するアクセサー合成の動作には違いがあります(「ランタイムの違い」も参照)。

  • レガシーランタイムの場合、インスタンス変数は現在のクラスの@interfaceブロックで既に宣言されている必要があります。プロパティと同じ名前のインスタンス変数が存在し、その型がプロパティの型と互換性がある場合は、それが使用されます。それ以外の場合は、コンパイラエラーが発生します。

  • 最新のランタイム(Objective-Cランタイムプログラミングガイドの「ランタイムバージョンとプラットフォーム」を参照)の場合、インスタンス変数は必要に応じて合成されます。同じ名前のインスタンス変数がすでに存在する場合は、それが使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.