web-dev-qa-db-ja.com

Objective-Cのプロパティとインスタンス変数

Objective-Cのプロパティとインスタンス変数については、少し混乱しています。

私はアーロン・ヒレガスの「Mac OS X用のCocoaプログラミング」の半分ほどのところにあり、すべてが論理的です。次のようなクラスを宣言します。

@class Something;

@interface MyClass : NSObject {
    NSString *name;
    NSArray *items;

    Something *something;

    IBOutlet NSTextField *myTextField;
}

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *items;
  • 他のオブジェクトはnameおよびitemsインスタンス変数を操作する必要があるため、@property/@synthesizeを使用してそれらのアクセサー/ミューテーターを生成します。クラス内では、アクセサー/ミューテーターを使用せず、インスタンス変数を直接操作するだけです。

  • somethingは、クラスで使用する単なるインスタンス変数であり、他のユーザーが使用する必要がないため、アクセサーとミューテーターのペアを作成しません。

  • UIでテキストフィールドを操作する必要があるため、IBOutletを宣言して接続し、完了です。

すべて非常に論理的です。

ただし、iPhoneの世界では状況が異なります。人々はすべてのインスタンス変数のプロパティを宣言し、IBOutletsのプロパティを宣言し、アクセサ/ミューテータを使用してインスタンス変数とやり取りしますwithinクラス(たとえば、[self setName:@"Test"]と書きます) name = @"Test"より)。

どうして?何が起こっている?これらの違いはiPhone固有ですか?すべてのインスタンス変数のプロパティを宣言し、IBOutletsのプロパティを宣言し、独自のクラス内でアクセサー/ミューテーターを使用する利点は何ですか?

55
Steve Harrison

IPhoneの世界では、ガベージコレクターは利用できません。参照カウントでメモリを注意深く管理する必要があります。これを念頭に置いて、次の違いを検討してください。

name = @"Test";

そして

self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];

事前の考慮なしにインスタンス変数を直接設定すると、以前の値への参照が失われ、保持カウントを調整できなくなります(releasedを手動で設定する必要があります)。プロパティを通じてアクセスすると、新しく割り当てられたオブジェクトの保持カウントがインクリメントされるとともに、自動的に処理されます。

基本的な概念はiPhone固有ではありませんが、ガベージコレクターがない環境では重要になります。

29
Mehrdad Afshari

インスタンス変数のアクセサーを生成するためにプロパティが使用されます。魔法は起こりません。

同じアクセサーを手動で実装できます。

Aaron Hillegassの本のメンバー変数の3つのメモリ管理戦略の例をご覧ください。それらはassign/copy/retainです。特定の変数に必要なものを1つ選択します。

Objective-cのメモリ管理について理解していると思います...

アクセサは、各変数のメモリ管理の複雑さと違いを隠します。

例えば:

name = @"Test"

は単純な割り当てであり、nameNSString @"Test"への参照を保持するようになりました。ただし、copyまたはretainを使用することもできます。アクセサーを選択したメモリ管理のバージョンに関係なく、複雑さを隠し、常に(または同様の)変数にアクセスします。

[self setName:@"Test"] 
[self name]

これでsetName:assign/copy or retainを使用する可能性があるため、心配する必要はありません。

私の推測では、iPhoneチュートリアルではプロパティを使用して、新しい開発者がメモリ管理を簡単にジャンプできるようにしています(ただし、毎回手動で実装するのではなく、プロパティを使用して適切なアクセサを生成する方が便利です)。

6
stefanB

ただし、iPhoneの世界では状況が異なります。人々は、すべてのインスタンス変数のプロパティを宣言し、IBOutletsのプロパティを宣言し、アクセサ/ミューテータを使用してクラス内のインスタンス変数とやり取りします(たとえば、[self setName:@"Test"] のではなく name = @"Test")。

これはiPhone固有ではありません。 initメソッドとdeallocメソッドを除いて、常にアクセサーを使用することをお勧めします。特にMac(Cocoaバインディングを使用)の主な利点は、アクセサーを使用すると無料のKVO通知が送信されることです。

「すべての単一インスタンス変数のプロパティを宣言する」理由は、ほとんどの場合、インスタンス変数のすべてがプロパティとして公開したいものだからです。プライベートにしたいものがあれば、ヘッダーファイルでそのプロパティを宣言しません。 (ただし、前述の無料のKVO通知を取得するために、実装ファイルのクラス拡張でプロパティを作成する場合があります。)

私の意見では、アウトレットのプロパティを宣言するのはやり過ぎです。それに意味がありません。プロパティを作成しない場合、nibローダーは、インスタンス変数への直接アクセスによってアウトレットを設定します。これは、そのタスクには問題ありません。

3
Peter Hosey

現代の開発では、ベストプラクティスを特定、定義、および適用するための非常に強力な試みが行われたことをお勧めします。

これらのベストプラクティスには、継続性と一貫性があります。

initメソッドとdeallocメソッドでのアクセサーの使用についての議論とは別に、アクセサーは通常、クラスの内部と外部で常に提供されている利点のために カプセル化 、ポリモーフィックvar実装(どちらも抽象化とリファクタリングを可能にします)、および継続性と一貫性のベストプラクティスを促進します。オブジェクト指向言語の基本的な利点は、このようにして言語の機能を最大限に活用するときに発揮されます。上級プログラマは通常、証明するように、常にコーディングの一貫性を保つことはしばしば言及されない利点です。

2
JRT

このように書けます

//MyClass.h

@class Something;

@interface MyClass : NSObject 

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *items;

@end 

//MyClass.m
@interface MyClass() 

@property (nonatomic, strong) IBOutlet NSTextField *myTextField;
@property (nonatomic, strong) Something *something;

@end
0
Shafraz Buhary