web-dev-qa-db-ja.com

すべてのivarはプロパティである必要がありますか?

特に、メモリ管理に役立つ利点があるため、インスタンス変数へのアクセスにプロパティを使用する必要があることは、iOSのコーディングのあらゆる場所で推奨されています。

このアドバイスは私にはあまりよくありません。プレーンな古いivarの代わりにプロパティを使用すると、コードが多すぎて、メモリ管理に慣れている場合の利点がわかりません。それは本当に重要ですか?インスタンス変数を管理するためのアプローチは何ですか?

56
Diego

すべてのivarのプロパティを宣言する必要はありません。いくつかの点が頭に浮かびます:

  • Ivarがオブジェクトの存続期間中に一度だけ割り当てられる場合、プロパティを宣言しても実際には何も得られません。 init中に保持/コピー/割り当てを行い、dealloc中に必要に応じて解放します。
  • Ivarが頻繁に変更される場合は、プロパティを宣言し、常にアクセサーを使用すると、メモリ管理エラーを回避しやすくなります。
  • プロパティとivarがプライベートであることが意図されている場合は、.hファイルではなく.mファイルのクラス拡張でプロパティを宣言できます。
  • IOS 4.0以降を対象とする場合、プロパティを定義してアクセサーを合成する場合、ヘッダーでivarを宣言する必要はありません。

したがって、通常はプロパティを使用しますが、NSMutableArrayなどのオブジェクトがinitの間に割り当てて、何でも束を保持するために使用する場合は、私は絶対に使用しないので、単純な古いivarを使用しますivarを再割り当てします。

77
Daniel Dickison

ダニエルの答えは正しいですが、重要な点を逃しています。つまり:

プレーンな古いivarの代わりにプロパティを使用すると、コードが多すぎて、メモリ管理に慣れている場合の利点がわかりません。

利点は一貫性です。一貫したメモリ管理と一貫した動作。

特に、これらの2行のコードは、実行時に実際に極端に異なるの動作をする可能性があります。

iVar = [foo retain];
self.iVar = foo;

1つ目はインスタンス変数の直接設定であり、変更通知はありません。 2番目はセッターを通過するため、セット時にサブクラスのカスタマイズを保持しますおよびプロパティのオブザーバーに変更が通知されることを保証します

コード全体(内部的にはクラスの内部)でivarを直接使用している場合outsideからインスタンスのivarを直接使用している場合、そうですね...コードベースで作業している請負業者は、2倍にする必要があります。レート;)の場合、変更通知の伝播を手動で処理する必要があります(通常はwillChangeValueForKey:/didChangeValueForKeyを呼び出すことによって)or依存するメカニズムの使用を回避するようにアプリケーションを明示的に設計しますKey-Valueの観察時。

あなたは「コードが多すぎる」と言います。わかりません。上記の2行のコードでは、ドット構文の方が文字が少なくなっています。従来の構文を使用してセッターメソッドを呼び出す場合でも、コードは少なくなります。

また、メモリ管理の一元化の価値を軽視しないでください。無数の呼び出しサイトとクラッシュシティでの1つの偶発的な脱落。

51
bbum

プロパティは、同じメソッドを何度も書くことを避けるための単なる構文糖です。プロパティを使用すると、古いオブジェクトを解放し、新しいオブジェクトを無料で保持するセッターがあります。

3
Simone D'Amico

プライベートフィールドの場合-プリミティブ型(BOOL/int/floatなど)に対してのみ直接ivarを使用するのが安全であることをお勧めします。プロパティのメモリ管理に関連して、ラッピングすべてを使用することをお勧めします。このアプローチの追加の利点は、IDEは通常、直接ivarへのアクセスを異なる方法で強調表示するため、常に単純なスカラーフィールドとオブジェクトタイプフィールドをうまく分離できます。

これとは対照的に、私はクラスパブリックインターフェイスの直接のivarを強く推奨しません。言語の動的な性質のため、検索、ローカライズ、修正が非常に難しいランタイムエラーが発生する可能性があります。次の階層を検討してください

_@interface BaseControl
...
@end

@interface Label : BaseControl
...
@end

@interface Button : BaseControl {
  @public
    BOOL enabled;
}
@end
_

とコードスニペット

_- (void)enableAllButtons {
    NSArray *buttons = [self getAllButtons];   // expected to contain only Button instances
    for (Button *button in buttons) {
        button->enabled = YES;
    }
} 
_

ここで、-getAllButtonsロジックのどこかにエラーがあり、Labelがその配列で返されることを想像してください。これらのLabelクラスインスタンスにはivarが割り当てられていません。意外なことに、この場合、-enableAllButtonsはクラッシュしません。しかし、その時点で、これらのLabelインスタンスの内部構造破損しているおよびこれwillは未定義の動作を引き起こし、他の場所で使用するとクラッシュします。

メモリ管理に関するいくつかの一般的な問題と同様に(そして、一般的に-ダングリングポインターによる)-この種の問題は、特定およびローカライズが困難です-通常、エラーの外観は(時間、コード、またはアプリフローの観点から)離れているためエラーの原因となる場所。しかし、その特定の問題があれば、それをローカライズして修正するのに役立つ便利なツール(リーク/ゾンビアナライザーなど)さえありません。それを再現する方法を学び、誤った状態を簡単に調査できる場合でもです。

明らかに@property (assign) BOOL enabled;を使用すると、-enableAllButtonsで実行時例外を簡単に診断および修正できます。

1
Max O