24

私はこのトピックに関する情報を見つけることができませんでした、そしてそれについて私が知っていることのほとんどは完全な偶然によるものです(そして私のコードが機能しなかった理由を理解しようと数時間試みました)。私が見つけたほとんどのチュートリアルは、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]を呼び出そうとしても、_highscoreの値が返されるため、何も変更されないことがわかりました。これは(私が思うに)test.hで設定されたivarです。したがって、test.mでの変数の変更はすべて、highscoreではなく_highscoreを変更する必要があります。(ここで間違っている場合は訂正してください)

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

わからないこと

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

4

5 に答える 5

38

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

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

いくつかの背景

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

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

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

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

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

プロ変数

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

プロのプロパティ

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

于 2012-07-13T20:51:09.530 に答える
5

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

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

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

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

1元の投稿で宣言した2つのivarを削除し、@property/ dynamicduoに任せます@synthesize

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

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

@implemenation Test
@synthesize timesPlayed;
@synthesize highscore;

...
于 2012-07-13T20:50:32.527 に答える
2

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

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

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

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

@synthesize propertyItem = _propertyItem; 

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

_propertyItem = @"Blah";

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

self.propertyItem = @"Blah";

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

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

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

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

于 2012-07-13T20:56:46.753 に答える
0

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

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

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

于 2012-07-13T20:50:08.790 に答える
0

これは古い質問かもしれませんが、「現代」では、@synthesize-は必要ありません。

@interface       SomeClass : NSObject
@property NSString * autoIvar;
@end
@implementation  SomeClass
- (id) init { return self = super.init ? _autoIvar = @"YAY!", self : nil; }
@end

_underscoredバッキングivarは自動的に合成されます...そしてこのクラスの実装内で直接(つまり、自動生成されたアクセサーを呼び出さずに)利用できますself

サブクラスが(を呼び出さずに)アクセスする機能をサポートする場合、または他の場所で説明されている他の無数の理由で、それを合成する必要があるだけです。_backingIvarself

于 2014-02-14T06:49:31.870 に答える