ブロックをそれ自体の中から再帰的に呼び出したいのですが。obj-cオブジェクトでは、「self」を使用するようになりますが、それ自体の内部からブロックインスタンスを参照するためにこのようなものはありますか?
4 に答える
楽しい話!ブロックは実際にはObjective-Cオブジェクトです。self
とはいえ、ブロックのポインターを取得するための公開されたAPIはありません。
ただし、ブロックを使用する前に宣言すると、再帰的に使用できます。ガベージコレクションされていない環境では、次のようにします。
__weak __block int (^block_self)(int);
int (^fibonacci)(int) = [^(int n) {
if (n < 2) { return 1; }
return block_self(n - 1) + block_self(n - 2);
} copy];
block_self = fibonacci;
に修飾子を適用する必要があります。そうしないと、内部の参照が割り当てられる前に修飾子を参照するためです(最初の再帰呼び出しでプログラムがクラッシュします)。これは、ブロックがそれ自体への強い参照をキャプチャしないようにするためです。これにより、メモリリークが発生します。__block
block_self
block_self
fibonacci
__weak
次の再帰的ブロックコードは、ARC、GC、または手動のメモリ管理を使用してコンパイルおよび実行され、クラッシュ、リーク、または警告(アナライザーまたは通常)を発行しません。
typedef void (^CountdownBlock)(int currentValue);
- (CountdownBlock) makeRecursiveBlock
{
CountdownBlock aBlock;
__block __unsafe_unretained CountdownBlock aBlock_recursive;
aBlock_recursive = aBlock = [^(int currentValue)
{
if(currentValue >= 0)
{
NSLog(@"Current value = %d", currentValue);
aBlock_recursive(currentValue-1);
}
} copy];
#if !__has_feature(objc_arc)
[aBlock autorelease];
#endif
return aBlock;
}
- (void) callRecursiveBlock
{
CountdownBlock aBlock = [self makeRecursiveBlock];
// You don't need to dispatch; I'm doing this to demonstrate
// calling from beyond the current autorelease pool.
dispatch_async(dispatch_get_main_queue(), ^
{
aBlock(10);
});
}
重要な考慮事項:
- ブロックを手動でヒープにコピーする必要があります。そうしないと、別のコンテキストからブロックを呼び出すときに、存在しないスタックにアクセスしようとします(ARCは通常これを行いますが、すべての場合ではありません。安全に再生することをお勧めします)。
- 2つの参照が必要です。1つはブロックへの強参照を保持し、もう1つは再帰ブロックが呼び出すための弱参照を保持します(技術的には、これはARCでのみ必要です)。
- ブロックがブロック参照のまだ割り当てられていない値をキャプチャしないように、__block修飾子を使用する必要があります。
- 手動でメモリ管理を行っている場合は、コピーしたブロックを自分で自動解放する必要があります。
__block
ブロック変数を次のように宣言する必要があります。
typedef void (^MyBlock)(id);
__block MyBlock block = ^(id param) {
NSLog(@"%@", param);
block(param);
};
self
ブロックはありません(まだ)。次のように作成できます(ARCを想定)。
__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
// Use blockSelf here
} copy];
blockSelf = block;
// Use block here
ブロックの作成後にブロックに__block
設定できるようにするために必要です。そうしないと、ブロックがそれ自体への強い参照を保持し、強い参照サイクルが発生してメモリリークが発生するため、が必要になりますblockSelf
。__weak
ブロックがヒープにコピーされていることを確認するcopy
ために必要です。新しいバージョンのコンパイラではこれは不要かもしれませんが、害はありません。