ココアObjective-Cクラスの変数の前にある下線はどのように機能しますか?


157

iPhoneのいくつかの例で、属性が変数の前にアンダースコア_を使用していることを確認しました。これが何を意味するのか誰か知っていますか?またはそれはどのように機能しますか?

私が使用しているインターフェイスファイルは次のようになります。

@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

上記のことは正確にはわかりませんが、ミッション名を次のように設定しようとすると:

aMission.missionName = missionName;

エラーが発生します:

構造体または共用体ではない何かのメンバー 'missionName'のリクエスト

回答:


97

ivarにアンダースコアプレフィックスを使用する場合(これは一般的な規則にすぎませんが、便利なものです)、自動生成されたアクセサー(プロパティ用)が使用するivarを認識できるように、追加の処理を1つ行う必要があります。具体的には、実装ファイルでは、次のようにsynthesizeなります。

@synthesize missionName = _missionName;

より一般的には、これは:

@synthesize propertyName = _ivarName;

78
自動合成プロパティでは、これはもう必要ありません。Xcodeは、@ property xxxxと_xxxxというivarを舞台裏で合成します。きちんと。
LearnCocos2D 2012年

@ LearnCocos2Dこんにちは!ここにiOSの初心者がいて、明確にする必要があることがあります。この間ずっと、私がしたことはproperty.hファイルで宣言し、.mファイルでそのselfようにアクセスしましたself.someProperty。これは正しい方法ですか?または、コードでivarを使用する必要がありますか?
Isuru 2013

ivarを設定してもプロパティセッターは実行されません-特定のケースごとにそれが適切かどうかを決定します
LearnCocos2D

Noobの質問:ivarを直接使用しないのはなぜですか?ivarを保持するために別のvarを宣言する必要があるのはなぜですか?
アレン

1
@アレン、あなたの質問を正しく理解している場合:宣言している個別の変数は、実際の変数へのポインタです。これはいくつかの理由で重要です(私が知っていることです)。最初に、ポインタを関数に渡すとき、その値を複製していません。使用する値を見つける場所を関数に伝えるだけです。これは、使用メモリを低く保つのに役立ちます(また、Javaで見つかる「ガベージコレクション」がない場合に重要なメモリの割り当てと割り当て解除にも役立ちます)
David Sigley

18

これは読みやすさのための規約であり、コンパイラーに対して特別なことは何もしません。あなたは人々がプライベートなインスタンス変数とメソッド名でそれを使うのを見るでしょう。Appleは実際にはアンダースコアを使用しないことを推奨しています(注意しないと、スーパークラスで何かをオーバーライドできる可能性があります)が、そのアドバイスを無視しても気にしないでください。:)


19
私が理解していることから、Appleはメソッド名にアンダースコアプレフィックスを使用しないことをお勧めします(プライベートメソッドの規約としてそれ自体のために予約されています)が、インスタンス変数名に関するそのような推奨はありません。
ケラン

9
@Kelan実際には、Apple はそうすることを推奨しています。「通常、インスタンス変数に直接アクセスするのではなく、代わりにアクセサメソッドを使用する必要があります(initおよびdeallocメソッドでインスタンス変数に直接アクセスします)。アンダースコア(_)を含む変数名。例:\ @implementation MyClass {BOOL _showsTitle;} "
dmirkitanov

iOS開発者ライブラリ内のすべての独自のサンプルコードには()が含まれていないため、実際にはAppleがそうすることを推奨しているとは思いませんAppleはまた、それを予約したと言っています。つまり、UIKitなどの独自のフレームワークのために内部で使用する必要があります。それが、不用意に使用しないようにする理由です。しかし、私はあなたが@kelanを提供したリンクでそれを見ます。彼らは実際に「改訂履歴」で使用することが「適切」であると述べています()。必要に応じて使用できると解釈しています。
WYS 2013

メソッド名にアンダースコアプレフィックスを使用しないように指示するAppleのドキュメントはこちらです。
ThomasW 2015

9

私が見た唯一の有用な目的は、前述のようにローカル変数とメンバー変数を区別することですが、これは必須の規則ではありません。@propertyと組み合わせると、syntheseステートメントの冗長性が増し@synthesize missionName = _missionName;、どこでも醜くなります。

アンダースコアを使用する代わりに、競合しないメソッド内で説明的な変数名を使用してください。それらが競合する必要がある場合、メソッド内の変数名には、複数のメソッドで使用される可能性のあるメンバー変数ではなく、アンダースコアが必要です。これが役立つ唯一の一般的な場所は、セッターまたはinitメソッド内です。さらに、@ synthesizeステートメントがより簡潔になります。

-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

編集: 自動合成の最新のコンパイラー機能により、私はivarにアンダースコアを使用します(まれに、自動合成と一致させるためにivarを使用する必要があります。


それは逆です。プライベート変数には下線が引かれています。プロパティではありません。そしてそれらを結合するそれらを合成するwhem。
Justin

これは、「プライベート変数」ではなく「メンバー変数」と呼んだことを除いて、私が説明したとおりです。
Peter DeWeese 2011

痛い!これは問題を求めています...自動合成はivar _myStringを作成します。つまり、セッターは機能しません(メソッドパラメーターからivarを認識できないため)。
geowar 2015

正解です。アップルが自動合成を追加したときに最後に編集を追加したのはそのためです。
Peter DeWeese 2015

5

これは実際には何の意味もありません。これは、一部の人々がメンバー変数とローカル変数を区別するために使用する規則にすぎません。

エラーに関しては、aMissionのタイプが間違っているようです。それは何の宣言ですか?


IDEではIntelliSenseが一般的です。メンバー/モジュール/クラス変数がリストの一番上に表示されます。別の一般的なprevixは "m_"です
STW

1
上記の例のように、何も意味がない場合、_missionNameとMissionNameをどのように切り替えることができますか?私の宣言は次のようになります。ミッション* aMission = [[Mission alloc] init]; aMission.missionName = @ "ミッション";
Atma

1
1つはインスタンス変数で、もう1つはプロパティです。aMission.missionNameのような構文ではインスタンス変数にアクセスできません。その構文はポインターでは機能しないためです。
チャック

また、Missionオブジェクトを操作しようとしているが、missionNameプロパティを使用して投稿したインターフェイスがMissionCellであることに注意してください。
smorgan 2009

2

これは、合成プロパティの命名規則専用です。

.mファイル内の変数を合成すると、Xcodeは自動的に_variableインテリジェンスを提供します。


1

アンダースコアを使用すると、self.member構文を使用せずにivarを解決できるだけでなく、変数がivar(アンダースコアのプレフィックスのため)またはメンバー引数(アンダースコアがないため)であることを知っているため、コードが読みやすくなります。 )。

例:

- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}

この例では、self.image(または[self image])の使用法の比較も見るとよいでしょう。self.imageを使用した方が良い場合と、_imageを使用した方が良い場合はいつですか?
Boeckm

2
@Boeckm:通常、self.imageプロパティにアクセスするを使用する必要があります。インスタンス変数に_image直接アクセスする必要があるのは、initメソッドとメソッド内のみです。dealloc他のメソッドを呼び出すと危険になる場合があります(オブジェクトが半分初期化または半分割り当て解除されているため)。
Peter Hosey、2012年

1

これは、self.variableNameと_variablenameに関する質問の「マスター」アイテムのようです。ループのために私を驚かせたのは、.hで、

...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

これにより、self.variableNameと_variableNameが.m内の2つの異なる変数になります。私が必要としたのは:

...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

次に、クラスの.mでは、self.variableNameと_variableNameは同等です。

私がまだはっきりしないのは、これが行われなくても、多くの例が依然として機能する理由です。

レイ


0

アンダースコアの代わりにself.variable名を使用するか、変数を合成してアンダースコアなしで変数またはアウトレットを使用できます。


2
同じクラスの変数だけが必要な場合は、.mファイル自体で宣言するだけで、自己やアンダースコアなしで呼び出すことができます
Ansal Antony

0

他の答えから欠落しているのは、を使用_variableするとvariable、(おそらく意図された)プロパティではなく、ぼんやりと入力してivarにアクセスできなくなることです。

コンパイラーは、self.variableまたはのいずれかを使用するように強制します_variable。アンダースコアを使用するとvariable、を入力できなくなり、プログラマーのエラーが減少します。

- (void)fooMethod {

    // ERROR - "Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

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