2

ブロックのドキュメントから:

参照カウント環境では、ブロック内で Objective-C オブジェクトを参照すると、デフォルトで保持されます。これは、オブジェクトのインスタンス変数を参照するだけの場合でも当てはまります。

作業が実行される前にブロックがオブジェクトに与えられ、作業が実行された後にブロックがレシーバーによって実行される完了ハンドラーパターンを実装しようとしています。私は良いメモリ市民であるため、ブロックは完了ハンドラーで参照するオブジェクトを所有する必要があり、ブロックがスコープ外になると解放されます。copyブロックは、それが宣言されたスタック スコープを通過しても存続するため、ブロックをヒープに移動する必要があることは十分にわかっています。

ただし、オブジェクトの 1 つが予期せず割り当て解除されています。いくつか遊んだ後、ブロックがヒープにコピーされたときに特定のオブジェクトが保持されていないように見えますが、他のオブジェクトは保持されています。何が間違っているのかわかりません。私が作成できる最小のテストケースは次のとおりです。

typedef void (^ActionBlock)(UIView*);

いくつかのメソッドの範囲内:

NSObject *o = [[[NSObject alloc] init] autorelease];
mailViewController = [[[MFMailComposeViewController alloc] init] autorelease];
NSLog(@"o's retain count is %d",[o retainCount]);
NSLog(@"mailViewController's retain count is %d",[mailViewController retainCount]);
ActionBlock myBlock = ^(UIView *view) {
       [mailViewController setCcRecipients:[NSArray arrayWithObjects:@"test@recipient.com",nil]];
       [o class];
    };
NSLog(@"mailViewController's retain count after the block is %d",[mailViewController retainCount]);
NSLog(@"o's retain count after the block is %d",[o retainCount]);
Block_copy(myBlock);
NSLog(@"o's retain count after the copy is %d",[o retainCount]);
NSLog(@"mailViewController's retain count after the copy is %d",[mailViewController retainCount]);

ある時点で両方のオブジェクトがブロックによって保持されることを期待しており、それらの保持カウントが同じであることは確かです。代わりに、次の出力が得られます。

o's retain count is 1
mailViewController's retain count is 1
mailViewController's retain count after the block is 1
o's retain count after the block is 1
o's retain count after the copy is 2
mailViewController's retain count after the copy is 1

o( のサブクラスNSObject) は適切に保持されており、範囲外にはなりません。ただしmailViewController、保持されず、ブロックが実行される前に割り当てが解除されるため、クラッシュが発生します。

4

3 に答える 3

5

-retainCount は使用しないでください。

オブジェクトの絶対保持カウントは無意味です。

releaseオブジェクトを保持させたのとまったく同じ回数呼び出す必要があります。それ以下ではなく (リークが好きでない限り)、もちろんそれ以上でもありません (クラッシュが好きでない限り)。

詳細については、メモリ管理ガイドラインを参照してください。

(@bbumの回答の1つから引用)


あなたの質問について:

実際にクラッシュを観察していますか?それとも、腰からやみくもに撃って、クラッシュするかもしれないと思っていますか?

投稿したコードから、インスタンス変数のように見えます。この場合、インスタンス変数の代わりにmailViewControllerブロックが保持されます。selfそして、autoreleasedインスタンス変数を作成したので、期待どおりにクリーンアップされていNSAutoreleasePoolます。

要約すると:

  1. 使用しないでください-retainCount
  2. autorelease実行ループのこのターンを超えて存在させたい変数をインスタンス化しないでください。

編集もう少し明確に:

ブロックが作成されると、次のようになります。

  1. スコープ内のオブジェクト参照を検査します。との 2 つがあり self->mailViewControllerますo
  2. self->mailViewController構造体 ( self) のメンバーであるため、直接保持されません。代わりに保持selfします。
  3. oローカル変数です。それを保持します。

これは適切な動作です。あなたのコードは...

  1. o+0 保持カウントで作成されます
  2. self->mailViewController+0 保持カウントで作成されます
  3. myBlock+0 保持カウントで作成されます。 oは +1 RC を持ち、 もそうselfです。 self->mailViewControllerまだ+0のRCを持っています
  4. myBlockコピーされる => +1 リテインカウント

この実行ループ サイクルの終わりまで早送りします。

  1. 現在の自動解放プールは排出されます。保持カウントが +0 のすべてのオブジェクトは、 を含めて割り当て解除されますself->mailViewControllerself->mailViewController現在、割り当て解除されたメモリを指しており、本質的にガベージです。

myBlockが実行されると、ある未来の時点に早送りします

  1. myBlockでメソッドを呼び出そうとしself->mailViewControllerます。ただし、self->mailViewController有効なオブジェクトを指しなくなり、アプリがクラッシュします。

ただし、mailViewControllerがインスタンス変数でない場合は、さらにコードを確認する必要があります。あなたが見ている動作がブロックのランタイムの問題である可能性は非常に低いと思いますが、可能性はあります。

于 2011-01-03T20:50:03.663 に答える
2

ドキュメントはもはやそれを言っていません。正しく言うようになりました:

手動で参照カウントされる環境では、ブロック内で使用されるローカル変数は、ブロックがコピーされるときに保持されます。

于 2012-09-13T19:16:49.603 に答える
-2

「mailViewController」は現在のクラス インスタンスのメンバーであるため、ブロックは実際にはここで「self」を保持します。

于 2012-09-12T22:28:05.323 に答える