Xcode 4で新しいプロジェクトを作成する場合、ボイラープレートコードは、実装ファイルのivarを次のように合成するときにアンダースコア文字を追加します。
@synthesize window = _window;
または:
@synthesize managedObjectContext = __managedObjectContext;
誰かがここで何が達成されているか教えてもらえますか?私は完全なナブではありませんが、これはObjective-Cの1つの側面であり、理解できません。
混乱の別のポイント。アプリのデリゲート実装では、上記のようにウィンドウiVarを合成した後、アプリケーションのdidFinishLaunchingWithOptions:メソッドでは、selfとviewController ivarsがselfを使用して参照されます。
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
しかし、deallocメソッドでは、_windowまたは_viewControllerです
ありがとう
これは、Objective-Cランタイムの以前のバージョンのアーティファクトです。
元々、@synthesize
はアクセサメソッドの作成に使用されていましたが、ランタイムではインスタンス変数を明示的にインスタンス化する必要がありました。
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
人々はインスタンス変数にプレフィックスを付けてプロパティと区別します(Appleはアンダースコアを使用したくないが、それは別の問題です)。インスタンスを指すようにプロパティを合成します)しかし、ポイントは、_qux
はインスタンス変数であり、self.qux
(または[self qux]
)はオブジェクトqux
に送信されるメッセージself
です。
インスタンス変数を-dealloc
で直接使用します。代わりにアクセサメソッドを使用すると、次のようになります(理由は簡単に説明しますが、お勧めしません)。
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
これには、qux
を解放し、参照をゼロにする効果があります。しかし、これには不幸な副作用があります:
qux
への変更を監視している可能性があります。これは、アクセサメソッドを使用して変更すると記録されます。nil
- messagingのセマンティクスのため、アクセサーを使用してnil
に設定したことは決してわかりません。インスタンス変数を直接解放し、参照をゼロ化しない場合、割り当て解除されたオブジェクトにアクセスすると、大きなEXC_BAD_ACCESS
が発生します。ランタイムの新しいバージョンでは、アクセサーメソッドに加えてインスタンス変数を合成する機能が追加されました。これらのバージョンのランタイムでは、インスタンス変数を省略して上記のコードを記述できます。
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
これは、実際に_qux
と呼ばれるFoo
上のインスタンス変数を合成します。この変数は、getterおよびsetterメッセージ-qux
および-setQux:
によってアクセスされます。
これに反対することをお勧めします。それは少し厄介ですが、アンダースコアを使用する理由が1つあります。つまり、偶発的な直接ivarアクセスから保護するためです。生のインスタンス変数を使用するのか、アクセサメソッドを使用するのかを覚えていると自分が信頼できると思う場合は、代わりに次のようにしてください:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
次に、インスタンス変数に直接アクセスしたい場合は、qux
(C構文のself->qux
に変換して、ポインターからメンバーにアクセスします)と言うだけです。アクセサーメソッド(オブザーバーに通知し、他の興味深いことを行い、メモリ管理に関してより安全で簡単にする)を使用する場合は、self.qux
([self qux]
)およびself.qux = blah;
([self setQux:blah]
)を使用します。
ここで悲しいことは、Appleのサンプルコードとテンプレートコードがひどいことです。適切なObjective-Cスタイルのガイドとして使用しないでください。また、適切なソフトウェアアーキテクチャのガイドとして使用しないでください。 :)
別の理由があります。インスタンス変数に下線を付けないと、パラメーターself.title = title
およびself.rating = rating
:
@implementation ScaryBugData
@synthesize title;
@synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
@end
インスタンス変数に下線を引くことにより、警告を回避します。
@implementation ScaryBugData
@synthesize title = _title;
@synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
@end
アプリケーションのdidFinishLaunchingWithOptions:メソッドでは、windowおよびviewController ivarsはselfを使用して参照されます
いいえ、そうではないです。これらはpropertieswindow
およびviewController
への参照です。これがアンダースコアのポイントです。プロパティが使用されているとき(アンダースコアなし)、およびivarが直接アクセスされているとき(アンダースコアを使用)を明確にするためです。
はい、オブジェクトの参照を区別するだけです。つまり、オブジェクトが直接参照される場合はアンダースコアを使用し、そうでない場合はselfを使用してオブジェクトを参照します。