web-dev-qa-db-ja.com

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

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

これはまだ有効ですか?そして、それは私の前の例とどのような違いがありますか?

102
indragie

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

@synthesizeプロパティ、ivarは実際に合成されます。これは、「fragile-ivar」シナリオを回避します。詳細については、 Cocoa with Love をご覧ください。

94
jbrennan

インターフェースでは、ブレースの間でインスタンス変数を正式に宣言するか、ブレースの外側の_@property_を介して、またはその両方で宣言できます。いずれにしても、それらはクラスの属性になります。違いは、_@property_を宣言すると、_@synthesize_を使用して実装でき、ゲッター/セッターを自動コーディングできることです。自動コーダーのセッターは、整数を初期化し、たとえばゼロに浮動します。インスタンス変数を宣言し、対応する_@property_を指定しない場合、_@synthesize_およびmustを使用して独自のゲッター/セッターを作成することはできません。

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

_@property_宣言メソッドでは、retainreadonlyなどの他のオプションも使用できますが、これらはインスタンス変数宣言メソッドでは使用できません。基本的に、ivarは古い方法であり、_@property_はそれを拡張し、より面白く/簡単にします。自己を使用して参照できます。名前がそのクラスに固有である限り、プレフィックスかどうかは関係ありません。それ以外の場合、スーパークラスがあなたと同じプロパティ名を持っているなら、話している名前を指定するためにself.nameまたはsuper.nameのように言わなければなりません。

したがって、中括弧の間にivarsを宣言する人が少なくなり、代わりに_@property_を指定してから_@synthesize_を実行するようになります。対応する_@synthesize_なしでは、実装で_@property_を実行できません。 Synthesizerは、_@property_仕様から属性のタイプのみを認識します。合成ステートメントでは、プロパティの名前を変更することもできます。これにより、コード内で1つの名前(略記)でプロパティを参照できますが、.hファイルでは外部でフルネームを使用できます。ただし、XCodeにある非常にクールなオートコンプリートでは、これはあまり利点ではありませんが、まだあります。

これが、あちこちに浮かんでいるすべての混乱と誤報を解消するのに役立つことを願っています。

71
PapaSmurf

両方の方法で動作しますが、中括弧で宣言しないと、デバッガーでxcodeの値が表示されません。

8
rickm

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;
3
Shafraz Buhary

ドキュメントから:

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

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

3
Charlie Elliott

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

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

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

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

1
Nate