Objective Cでのオブジェクトの割り当てと初期化
-
03-07-2019 - |
質問
オブジェクトを割り当てて初期化する次の2つの方法の違いは何ですか?
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
and
self.aController= [[AController alloc] init];
リンゴの例のほとんどは、最初の方法を使用しています。なぜ割り当て、初期化、オブジェクトし、すぐに解放するのですか?
解決
すべてのオブジェクトには参照カウントがあります。 0になると、オブジェクトの割り当てが解除されます。
プロパティが @property(retain)として宣言されていると仮定
:
最初の例、行ごと:
- オブジェクトは
alloc
によって作成され、参照カウントは1です。 - オブジェクトは
self
のsetAController:
メソッドに渡され、retain
メッセージが送信されます(メソッドはオブジェクトがどこから来たかを知る)、参照カウントを2に増やします。 - 呼び出し元のコードはオブジェクト自体を必要としないため、
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
はオブジェクトの所有権を主張しておらず、他の誰かがそれを保持する必要があります。この場合、最初の例は正しくありません。これらの種類のプロパティはまれであり、通常はオブジェクトデリゲートにのみ使用されます。
他のヒント
他の人が指摘したように、表示する2つのコードスニペットは同等ではありません(メモリ管理の理由から)。 前者が後者よりも選ばれる理由について:
後者の正しい定式化は次のようになります
self.aController= [[[AController alloc] init] autorelease];
前者と比較して、これは自動解放プールの使用により追加のオーバーヘッドを追加し、状況によってはオブジェクトの寿命が不必要に延長され(自動解放プールが解放されるまで)、アプリケーションのメモリフットプリントが増加します。
他の「可能」な実装(例の出所による)は単純です:
aController = [[AController alloc] init];
ただし、インスタンス変数を直接設定することは、initメソッドまたはdeallocメソッド以外の場所では強く推奨されません。その他の場所では、常にアクセサメソッドを使用する必要があります。
これにより、サンプルコードに示されている実装が行われます。
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
次の理由から、これはベストプラクティスに従います。
- 自動リリースを回避します。
- メモリ管理のセマンティクスをすぐに明確にします;
- アクセサメソッドを使用してインスタンス変数を設定します。
また、コードを1行に減らしたいという要望があるため、多くの人がAutoreleaseを使用していることに注意してください:
self.aController = [[[AController alloc] init] autorelease];
理論的には、iPhoneの自動リリースの方が多少高価です(その理由について明確な説明を聞いたことはありません)。
Xcodeを使用している場合、静的アナライザーでそのようなコードを検出するのに役立ちます。 [ビルド]をクリックします>>ビルドと分析
これにより、このようなコードで非常に役立つメッセージが表示されます。
注意すべきもう1つの点は、例がaControllerの@property定義にも依存していることです。
@property(readwrite、retain)id aController;
として定義されている場合、サンプルは機能しますが、 @property(readwrite、assign)id aController;
その後、releaseを余分に呼び出すと、オブジェクトの割り当てが解除されます。
することもできます
@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];
保持プロパティを使用すると、同じように機能しますが、混乱を少なくするために(プロパティを保持するために)別の方法を使用する方が適切です。 、実際にはsetAControllerが保持するためにそうではない場合。