web-dev-qa-db-ja.com

Objectivecでivarとプロパティを使用する理由

私はこのトピックに関する情報を見つけることができず、それについて私が知っていることのほとんどは完全な偶然によるものです(そして私のコードが機能しなかった理由を理解しようと数時間試みました)。私が見つけたほとんどのチュートリアルは、objective-cを学習しているときに、同じ名前の変数とプロパティを作成します。プロパティがすべての作業を実行し、変数がそこにあるように見えるため、重要性がわかりません。例えば:

Test.h

@interface Test : NSObject {
    int _timesPlayed, _highscore;
}

@property int timesPlayed, highscore;

// Methods and stuff

@end

Test.m

@implementation Test

  @synthesize timesPlayed = _timesPlayed;
  @synthesize highscore   = _highscore;

  // methods and stuff

@end

私が知っていること

1)さて、今日、私は(何時間もの混乱の後で)プロパティにいくら変更を加えてもhighscore = 5091231 [test highscore]を呼び出そうとしても、test.hで設定されたivarである_highscoreの値が返されるため、何も変更されません。したがって、test.mでの変数の変更はすべて、highscoreではなく_highscoreを変更する必要があります。 (ここで間違っている場合は訂正してください)

2)正しく理解している場合(おそらく理解していない場合)、test.hに設定されているivarは実際のメモリを表しますが、@ propertiesはそのメモリにアクセスするための単なる方法です。したがって、実装の外では、プロパティを経由せずに_highscoreにアクセスすることはできません。

わからないこと

基本的に、この状況について私が得られないのは、ivarを使用する必要があるかどうか、または@propertyと@synthesizeを使用できるかどうかです。 ivarは、実際には何もしないが私を混乱させる単なる余分なコードのようです。私が見た最近のtutsのいくつかは、ivarを使用していないようですが、使用しているものもあります。それで、これは単なるコーディングの好みですか、それとも実際に重要ですか? Appleのドキュメントを検索してみましたが、そこで迷子になり、探しているものが見つからないようです。どんなガイダンスでも大歓迎です。

22
CaldwellYSR

プロパティを合成するための構文は、@synthesize propertyName = variableNameと考えることができます。

これは、@synthesize highscore = _highscore;と書くと、_highscoreという名前の新しいivarが作成されることを意味します。したがって、必要に応じて、_highscore変数に移動することにより、プロパティが格納されている変数に直接アクセスできます。

いくつかの背景

あるバージョンのコンパイラーの前は、合成ステートメントがivarを作成しなかったことを覚えていません。代わりに、使用する変数のみが示されているため、変数とプロパティの両方を宣言する必要がありました。アンダースコアプレフィックスを使用して合成した場合、変数は同じプレフィックスを持つ必要がありました。これで、変数を自分で作成する必要がなくなりました。代わりに、合成ステートメントで指定したvariableNameの変数が作成されます(自分で宣言していない場合は、それだけです。プロパティのバッキング変数として使用されます)。

あなたのコードがしていること

変数を宣言するときにhighscoreという名前のivarを明示的に作成し、プロパティを合成するときに_highscoreという別のivarを暗黙的に作成します。これらは同じ変数ではないため、一方を変更しても、もう一方は何も変更されません。

変数を使用する必要がありますか?

これは本当に好みについての質問です。

プロ変数

self.をあちこちに書く必要がなければ、コードがきれいになると感じる人もいます。また、メソッド呼び出しを必要としないため、高速であるとも言われています(ただし、アプリのパフォーマンスに測定可能な影響を与えることはおそらくないでしょう)。

プロのプロパティ

プロパティの値を変更すると、必要なすべてのKVOメソッドが呼び出され、値が変更されたときに他のクラスに通知を受け取ることができます。デフォルトでは、プロパティへのアクセスもアトミックであるため(複数のスレッドからアクセスすることはできません)、プロパティは複数のスレッドからの読み取りと書き込みがより安全です(これは、プロパティが指すオブジェクトがスレッドセーフであることを意味しません。それは可変配列であり、複数のスレッドがそれでも本当に悪いことを壊す可能性があり、2つのスレッドがプロパティを異なるものに設定するのを防ぐだけです)。

37

あなたが提案したように、ivarsを宣言せずに@property@synthesizeを使用することができます。上記の問題は、@synthesizeがプロパティ名をコンパイラによって生成された新しいivarにマップしたことです。したがって、すべての目的と目的で、クラス定義は次のようになります。

@interface Test : NSObject {
int timesPlayed;
int highscore;
int _timesPlayed;
int _highscore;
}
...
@end

正しいivarを変更しなかったため、self.timesPlayedを介してアクセスした場合、ivar timesPlayedに直接値を割り当てても表示されません。

いくつかの選択肢があります。

1元の投稿で宣言した2つのivarを削除し、@property/@synthesizeダイナミックデュオに任せます。

22つのivarの前にアンダースコア「_」を付けるように変更します

3 @synthesizeステートメントを次のように変更します。

@implemenation Test
@synthesize timesPlayed;
@synthesize highscore;

...
4
gschandler

私は通常、@ propertyと@synthenizeを使用します。

@propertyは、プロパティの使用方法に関するコンパイラとユーザーの指示を提供します。天気それはセッターを持っています、そのセッターは何ですか。期待して返す値のタイプ。これらの命令は、オートコンプリート(および最終的にはクラスに対してコンパイルされるコード)と@synthesizeによって使用されます。

@synthesizeは、デフォルトで、プロパティと同じ名前のインスタンス変数を作成します(これは混乱する可能性があります)

私は通常、次のことを行います

@synthesize propertyItem = _propertyItem; 

これにより、デフォルトでゲッターとセッターが作成され、自動解放が処理され、インスタンス変数が作成されます。使用するインスタンス変数は_propertyItemです。インスタンス変数にアクセスしたい場合は、そのまま使用できます。

_propertyItem = @"Blah";

これは間違いです。常にゲッターとセッターを使用する必要があります。これにより、アプリがリリースされ、必要に応じて更新されます。

self.propertyItem = @"Blah";

これはそれを処理するためのより良い方法です。また、合成の= _propertyItemセクションを使用する理由は、次のことができないためです。

propertyItem = @"Blah"; // this will not work.

_propertyItemに置き換えることをお勧めします。ただし、代わりにself.propertyItemを使用する必要があります。

情報がお役に立てば幸いです。

2
The Lazy Coder

あなたの例では、@synthesize timesPlayed = _timesPlayed;_timesPlayedと呼ばれる新しいivarを作成し、プロパティはそのivarを参照します。 timesPlayedは完全に独立した変数であり、プロパティとはまったく関係がありません。 @synthesize timesPlayed;を使用するだけの場合、プロパティはtimesPlayedを参照します。

アンダースコア規則の目的は、プロパティを介して(つまり、合成されたsetterメソッドを介して)実行するときに、誤ってivarに直接割り当てないようにすることです。ただし、本当に必要な場合は、_timesPlayedに直接アクセスできます。プロパティを合成すると、ivarのゲッターとセッターが自動生成されます。

一般に、プロパティのivarを宣言する必要はありませんが、必要な特別な場合もあります。

0