web-dev-qa-db-ja.com

Objective Cでのオブジェクトの割り当てと初期化

オブジェクトを割り当てて初期化する次の2つの方法の違いは何ですか?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

そして

self.aController= [[AController alloc] init];

ほとんどのAppleの例では最初のメソッドを使用しています。なぜ割り当て、初期化、オブジェクトしてからすぐに解放しますか?

56
Ronnie Liew

すべてのオブジェクトには参照カウントがあります。 0になると、オブジェクトの割り当てが解除されます。

プロパティが@property (retain)として宣言されたと仮定します:

最初の例、行ごと:

  1. オブジェクトはallocによって作成され、参照カウントは1です。
  2. オブジェクトはselfの_setAController:_メソッドに渡され、retainメッセージを送信します(メソッドはオブジェクトの送信元を知らないため)。その参照カウントをインクリメントしますから2。
  3. 呼び出し元のコードはオブジェクト自体を必要としないため、releaseを呼び出して、参照カウントを1に減らします。

2番目の例では基本的にステップ1と2を実行しますが、3は実行しません。したがって、オブジェクトの参照カウントは2です。

ルールは、オブジェクトを作成した場合、それを使い終わったらリリースする責任があります。この例では、コードはプロパティを設定した後にtempAControllerで実行されます。そのオブジェクトを保持する必要がある場合、retainを呼び出すのはセッターメソッドの責任です。

Objective-Cの_self.property = foo;_は実際には_[self setProperty:foo];_の略記であり、_setProperty:_メソッドは必要に応じてオブジェクトを保持またはコピーすることを覚えておくことが重要です。

プロパティが@property (copy)と宣言された場合、オブジェクトは保持される代わりにコピーされます。最初の例では、元のオブジェクトはすぐに解放されます。 2番目の例では、元のオブジェクトの参照カウントは0であっても1になります。したがって、同じ方法でコードを記述できます。

プロパティが@property (assign)と宣言された場合、selfはオブジェクトの所有権を主張しておらず、他の誰かがそれを保持する必要があります。この場合、最初の例は正しくありません。これらの種類のプロパティはまれであり、通常はオブジェクトデリゲートにのみ使用されます。

70
benzado

他の人が指摘したように、表示する2つのコードスニペットは同等ではありません(メモリ管理の理由から)。前者が後者よりも選ばれる理由について:

後者の正しい定式化は

self.aController= [[[AController alloc] init] autorelease];

前者と比較して、これは自動解放プールの使用により追加のオーバーヘッドを追加し、状況によっては、オブジェクトの有効期間が不必要に延長され(自動解放プールが解放されるまで)、アプリケーションのメモリフットプリントが増加します。

他の「可能な」実装(例がどこにあるかによる)は単純です:

aController = [[AController alloc] init];

ただし、インスタンス変数を直接設定することは、initメソッドまたはdeallocメソッド以外の場所では強く推奨されません。その他の場所では、常にアクセサメソッドを使用する必要があります。

これにより、サンプルコードに示されている実装が行われます。

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

次の理由から、これはベストプラクティスに従います。

  • 自動解放を回避します。
  • メモリ管理のセマンティクスがすぐに明確になります。
  • アクセサメソッドを使用して、インスタンス変数を設定します。
30
mmalc

Xcodeを使用している場合、静的アナライザーでそのようなコードを検出するのに役立ちます。 [ビルド] >> [ビルドと分析]をクリックするだけです

alt text

これにより、このようなコードで非常に役立つメッセージが表示されます。

alt text

5
leviathan

また、コードを1行にまとめたいという要望があるため、多くの人がAutoreleaseを使用していることに注意してください。

self.aController = [[[AController alloc] init] autorelease];

理論的にはiPhoneの自動リリースは多少高価であるため(理由を明確に説明することはありません)、オブジェクトを他の場所に割り当てた直後に明示的にリリースすることができます。

注意すべきもう1つの点は、例がaControllerの@property定義にも依存していることです。

@property (readwrite, retain) id aController;として定義されている場合、サンプルは動作しますが、@property (readwrite, assign) id aController;として定義されている場合、releaseの追加呼び出しによりオブジェクトの割り当てが解除されます。

4
Ashley Clark

あなたもできる

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

保持プロパティを使用すると、同じように機能しますが、混乱を少なくするために(プロパティを保持するために)他の方法を使用する方が適切です。このコードにより、実際にaController setAControllerが保持するため、そうではありません。

2
mk12