0

このスレッドでいくつかのコードを見ていました-performSelector:withObject:afterDelay:? のように、遅延後にブロックをトリガーするにはどうすればよいですか? . ブロックが非同期的に何かを行う場合、いつブロックを解放する必要があるのか​​ 疑問に思っていましたか?

次のようなコードがあるとします。

- (void)testMethod:(id)parameter
{
    dispatch_block_t block = ^{
         SomeAsyncTask *t = [SomeAsyncTask withCompletionBlock:^{
                                 [parameter doAction];
                             }];    
    };
    [self performSelector:@selector(executeBlock:)
            onThread:backgroundThread
               withObject:block
            waitUntilDone:NO];
    dispatch_release(block); //I can release the block here because performSelector      retains the block
}

- (void)executeBlock:(id)block
{
    block();
}

その場合、SomeASyncTask の完了ブロックがパラメーターを保持するため、ブロックを安全に解放できることが重要ですか?

4

3 に答える 3

2

Ken Thomases の答えは正しいです。いただいたご意見には、より具体的にお答えしたいと思います。

まず、は直接同期呼び出しであるため、performSelector:withObject:またはと同じであるかどうかが明確ではありません。はあまり面白くないので、だと思います。performSelector:withObject:afterDelay:performSelector:withObject:[self performSelector:@selector(runBlock:) withObject:block_];[self runBlock:block_]performSelector:withObject:afterDelay:performSelector:withObject:

それを段階的に見てください。performSelector:withObject:afterDelay:引数を保持するため、ブロックを渡した後に解放できます。そして、そのセレクターのパフォーマンスを通じてperformSelector:...それを保持します。したがって、 の間、ブロックは によって保持されているため、有効です。ブロックの実行中も有効です (まだ の実行中にあるため)。非同期の場合、引数を保持する必要があります。等々。runBlockperformSelector:...runBlockdoSomethingAsynchronouslyWithCompletionBlock

しかし、あなたはそれをそのように見る必要はありません。よく考えてみると、メモリ管理ルールは、他のコードが何をするかを気にする必要がなく、ローカルで必要なものだけを気にする必要があるように作られていることがわかります。

メモリ管理ルールは次の条件に要約されます:すべての関数/メソッドは、呼び出されたときにその引数が有効であることを期待します(これは通常、呼び出し関数がこの時間中に実行されないため、関数呼び出しの期間を通じて有効であることを意味します。この関数が間接的にそれを削除するようなことをしない限り (辞書から削除するなど)、無効になることはありますか?); また、関数呼び出し後に有効である期間については期待していません。それでおしまい。すべてはこれからです。

たとえば、 ではdoWork、ブロックを使用する必要がある期間だけを気にします。以降は必要ないのでperformSelector:...、安心して解放できます。performSelector:...非同期で何かを行うことは問題ではありません。それが非同期であることさえ知らないかもしれません (たとえば、動的に呼び出す未知のメソッドを選択している可能性があります)。ポイントは、それが何をするかは問題ではないということです。なんで?performSelector:...は、呼び出したときよりも長く引数が有効であると想定しないためです。したがって、それをより長く保持する必要がある場合 (実際に保持する必要がある場合)、保持する必要があります (ただし、これを知る必要はありません)。そして、必要な限り保持します。

同様に、runBlock与えられた引数が呼び出しの間有効であると仮定できます。長く保持する必要がないため (ブロックを呼び出すだけです)、保持する必要はありません。ブロックはこれを変更しません。なんで?繰り返しになりますが、ブロックはその引数 (ブロック自体を含む) が呼び出し後に有効であると想定していないため、それrunBlockを保証する必要はありません。ブロックが を呼び出す場合、それでdoSomethingAsynchronouslyWithCompletionBlock問題ありません。doSomethingAsynchronouslyWithCompletionBlockは、その呼び出しを超えて何も有効であるとは想定していないため、本当に非同期である場合は、どこかに保持する必要があります。等

于 2012-06-08T21:21:52.803 に答える
1

呼び出し後すぐに解放できます-performSelector:withObject:afterDelay:。(after-delay バリアントを使用するつもりだったと思います。) いつものように、メモリ管理はユーザーが担当し、そのメモリ管理は他のコードが担当します。-performSelector:withObject:afterDelay:これは、セレクターが実行されるまで、渡されたレシーバーとオブジェクトを保持する必要があるという別の言い方です。

編集して追加:ところで、dispatch_after()リンク先の質問への回答に示されているように使用しないのはなぜですか?

于 2012-06-08T00:11:13.093 に答える
-2

引数で配列を渡してみるかもしれません。

于 2012-06-08T00:22:04.507 に答える