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:...
それを保持します。したがって、 の間、ブロックは によって保持されているため、有効です。ブロックの実行中も有効です (まだ の実行中にあるため)。非同期の場合、引数を保持する必要があります。等々。runBlock
performSelector:...
runBlock
doSomethingAsynchronouslyWithCompletionBlock
しかし、あなたはそれをそのように見る必要はありません。よく考えてみると、メモリ管理ルールは、他のコードが何をするかを気にする必要がなく、ローカルで必要なものだけを気にする必要があるように作られていることがわかります。
メモリ管理ルールは次の条件に要約されます:すべての関数/メソッドは、呼び出されたときにその引数が有効であることを期待します(これは通常、呼び出し関数がこの時間中に実行されないため、関数呼び出しの期間を通じて有効であることを意味します。この関数が間接的にそれを削除するようなことをしない限り (辞書から削除するなど)、無効になることはありますか?); また、関数呼び出し後に有効である期間については期待していません。それでおしまい。すべてはこれからです。
たとえば、 ではdoWork
、ブロックを使用する必要がある期間だけを気にします。以降は必要ないのでperformSelector:...
、安心して解放できます。performSelector:...
非同期で何かを行うことは問題ではありません。それが非同期であることさえ知らないかもしれません (たとえば、動的に呼び出す未知のメソッドを選択している可能性があります)。ポイントは、それが何をするかは問題ではないということです。なんで?performSelector:...
は、呼び出したときよりも長く引数が有効であると想定しないためです。したがって、それをより長く保持する必要がある場合 (実際に保持する必要がある場合)、保持する必要があります (ただし、これを知る必要はありません)。そして、必要な限り保持します。
同様に、runBlock
与えられた引数が呼び出しの間有効であると仮定できます。長く保持する必要がないため (ブロックを呼び出すだけです)、保持する必要はありません。ブロックはこれを変更しません。なんで?繰り返しになりますが、ブロックはその引数 (ブロック自体を含む) が呼び出し後に有効であると想定していないため、それrunBlock
を保証する必要はありません。ブロックが を呼び出す場合、それでdoSomethingAsynchronouslyWithCompletionBlock
問題ありません。doSomethingAsynchronouslyWithCompletionBlock
は、その呼び出しを超えて何も有効であるとは想定していないため、本当に非同期である場合は、どこかに保持する必要があります。等