Objective-Cのivarとプロパティの違いは何ですか


82

Objective-Cでivarとプロパティを使用するこれらの3つの方法の意味上の違いは何ですか?

1.1。

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;

2.2。

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;

3.3。

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}

回答:


57

番号1は、MyOtherObjectクラスを前方宣言して、コンパイラとリンカに表示されるコードの量を最小限に抑え、循環参照を回避する可能性があるという点で、他の2つとは異なります。この方法で行う場合は、#importを.mファイルに入れることを忘れないでください。

@property(および.m内の@synthesizeと一致する)ファイルを宣言することにより、指定した方法で処理されたメモリセマンティクスを使用してアクセサメソッドを自動生成します。ほとんどのオブジェクトの経験則は保持ですが、たとえばNSStringsはコピーを使用する必要があります。シングルトンとデリゲートは通常、割り当てを使用する必要があります。手書きのアクセサーは面倒でエラーが発生しやすいので、これにより多くの入力やばかげたバグを節約できます。

また、合成プロパティを宣言すると、次のようなドット表記を使用してアクセサメソッドを呼び出すことができます。

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 

通常のメッセージパッシング方法の代わりに:

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 

舞台裏では、実際には次のようなメソッドを呼び出しています。

- (void) setOtherObj:(MyOtherObject *)anOtherObject {

    if (otherObject == anOtherObject) {
        return;  
    }

    MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
    otherObject = [anOtherObject retain]; // put the new value in  
    [oldOtherObject release]; // let go of the old object
} // set it

…またはこれ

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it

お尻の全体的な痛み、右。次に、クラス内のすべてのivarに対してこれを実行します。正確に行わないと、メモリリークが発生します。コンパイラに作業を任せるのが最善です。

私はそれを参照番号1は、 IVARを持っていません。これがタイプミスではないと仮定すると、@ property / @synthesizeディレクティブがバックグラウンドでivarを宣言するので、問題ありません。これはMacOSXの新機能だと思います-SnowLeopardとiOS4。

3番にはこれらのアクセサーが生成されていないため、自分で作成する必要があります。アクセサメソッドに副作用を持たせたい場合は、上記のように標準のメモリ管理ダンスを実行してから、アクセサメソッド内で必要な副次的な作業を実行します。プロパティを合成するだけでなく、独自のプロパティを作成する場合はバージョンが優先されます。

私はすべてをカバーしましたか?


はい。ありがとうございます!私が言いたいのは、#1のフォワードクラスプラグマを取り出して#import "MyOtherObject"に置き換えると、コンパイル時エラーが発生するということです。理由は
わかり

アプローチ#1よりもアプローチ#2を使用する利点はありますか?
グレッグ

@Gregメソッド#1は、循環参照を防ぎます。stackoverflow.com/questions/7221174/を

3
ドット表記についてのビットを除いて、いい答えです。ドット表記に使用するためにプロパティを合成する必要はありません。実際、プロパティを宣言する必要はまったくありません。宣言されたセッターとゲッター(setFoo:およびなどfoo)がある限り、ドット表記を使用できます。
JeremyP 2012

関連性のために、ARCを使用している場合、合成は自動的に行われます。
ショーンラーキン

17

昔はivarがあり、他のクラスにそれらを設定または読み取らせたい場合は、ゲッター(つまり、-(NSString *)foo)セッター(つまり-(void)setFoo:(NSString *)aFoo;))を定義する必要がありました。

プロパティが提供するのは、ivarと一緒に無料で(ほぼ!)セッターとゲッターです。したがって、ここでプロパティを定義するときに、アトミック性(たとえば、複数のスレッドからの複数の設定アクションを許可するかどうか)、およびセマンティクスの割り当て/保持/コピー(つまり、セッターが新しい値をコピーする必要があるかどうか)を設定できます。または、現在の値を保存するだけです。別のクラスが、後で変更される可能性のある変更可能な文字列を使用して文字列プロパティを設定しようとしている場合に重要です)。

これが何をするか@synthesizeです。多くの人がivar名を同じままにしますが、合成ステートメントを作成するときに変更できます(つまり、プロパティに@synthesize foo=_foo;名前_fooを付けたivarを作成することを意味しますfoo。したがって、このプロパティを読み書きする必要があり、使用しない場合はself.foo、使用する必要があります_foo = ...-セッターとゲッターのみを通過したい場合は、ivarへの直接参照をキャッチするのに役立ちます)。

Xcode 4.6以降では、@synthesizeステートメントを使用する必要はありません。コンパイラは自動的にそれを実行し、デフォルトではivarの名前の前に_。を付けます。


1
プロパティのアトミック性はスレッドセーフを保証するものではないことに注意してください。
jscs 2012

つまり、アトミックなivarがある場合、セッターが設定している間、またはゲッターが取得しているときに、別のスレッドが起動していずれかを実行しようとすると、すべてがだまされてしまいますか?では、アトミックのポイントは何ですか?私の理解では、アトミックは少なくとも、ivarを設定すると、設定され、保持カウントが適切であることなどを確認します。それ以外の場合、なぜアトミックなのですか?[すべての問題を解決するだけで、だまされないようにするだけではありません]
David H

2
有効なオブジェクト全体を取得することが保証されています(ゲッターは割り当て解除中のオブジェクトを返しません)が、別のスレッドがセッターを使用している場合は、前または後から値を取得できます。ゲッターとセッターの外部で処理する必要があることを指定します。つまり、getterまたはsetter操作中にスレッドが中断されることはありませんが、操作の順序は定義されていません(このレベルでは、AFAIKにすることはできません)。
jscs 2012

さて、あなたの元のコメントは見当違いだったと主張します-アトミック性は尊重されます、スレッド経由でアクセスすると多くの問題が発生する可能性があります-したがって、私がこれまでに宣言したすべてのivarはアトミックであり、スレッドが含まれている場合は並行性他の場所で扱われます。
David H
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.