ご存じのとおり、ARC では__block
、ブロックで使用されるオブジェクト ポインター型の変数は、ブロックによって保持されます。したがって、次の単純化された例を見てください。
__block id foo = getObject();
void (^aBlock)() = ^ {
NSLog(@"%@", foo);
foo = getObject();
}
runBlockAsynchronouslyMultipleTimes(aBlock);
が指すオブジェクトfoo
はブロックによって保持されるため、ブロックが (非同期で) 実行されても、オブジェクトは引き続き有効であり、出力できます。ブロック内で割り当てを行うと、ARC は他の強参照と同様にそれを管理します (古い値は解放され、新しい値は保持されます)。(割り当てにより、最初に使用することが強制され__block
ます。) そして、ブロックが不要になると、ARC はそのfoo
時点で が指す保持オブジェクトを何らかの方法で解放します (リークされません)。
さて、MRC の下で同じことをしたいとしましょう (なぜ重要でないのか。これは言語に関する問題です)。ご存知のよう__block
に、ブロックで使用されるオブジェクト ポインター型の変数は、MRC のブロックによって保持されません。どちらでも構いません。自分たちで管理します (これは MRC です)。したがって、試行は次のようになります。
__block id foo = [getObject() retain];
void (^aBlock)() = ^ {
NSLog(@"%@", foo);
[foo release];
foo = [getObject() retain];
}
runBlockAsynchronouslyMultipleTimes(aBlock);
// where to release foo?
そのほとんどは簡単です。オブジェクトは、最初は手動で保持されます。ブロック内では、ポインターを再割り当てするときに、必要に応じて新しい値を解放して保持します。
しかし、問題は次のとおりです。ブロックが不要になったときにオブジェクトを解放するにはどうすればよいでしょうか。手動でメモリを管理するため、理想的には、ブロックの割り当てが解除されたときにオブジェクトを手動で解放する必要があります。しかし、これを行う簡単な方法はないようです。
おそらく1つの方法を考えることができます.連想参照を使用してオブジェクトをブロックに結び付けます。ただし、ブロック内で連想参照を再割り当てするには、ブロック自体への参照が必要になるため、ブロック変数も必要であり__block
、変数を設定する前にブロックをコピーする必要があります。これはすべて非常に醜いです。または、ブロックによって保持される変更可能なコンテナー オブジェクト内にオブジェクトを配置します。しかし、それも醜いです。