18

ブロックをそれ自体の中から再帰的に呼び出したいのですが。obj-cオブジェクトでは、「self」を使用するようになりますが、それ自体の内部からブロックインスタンスを参照するためにこのようなものはありますか?

4

4 に答える 4

27

楽しい話!ブロックは実際には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;

に修飾子を適用する必要があります。そうしないと、内部の参照が割り当てられる前に修飾子を参照するためです(最初の再帰呼び出しでプログラムがクラッシュします)。これは、ブロックがそれ自体への強い参照をキャプチャしないようにするためです。これにより、メモリリークが発生します。__blockblock_selfblock_selffibonacci__weak

于 2011-01-28T03:43:04.040 に答える
14

次の再帰的ブロックコードは、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修飾子を使用する必要があります。
  • 手動でメモリ管理を行っている場合は、コピーしたブロックを自分で自動解放する必要があります。
于 2012-05-12T03:06:54.710 に答える
6

__blockブロック変数を次のように宣言する必要があります。

typedef void (^MyBlock)(id);

__block MyBlock block = ^(id param) {
  NSLog(@"%@", param);
  block(param);
};
于 2011-01-28T03:43:46.650 に答える
3

selfブロックはありません(まだ)。次のように作成できます(ARCを想定)。

__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
        // Use blockSelf here
} copy];
blockSelf = block;
    // Use block here

ブロックの作成後にブロックに__block設定できるようにするために必要です。そうしないと、ブロックがそれ自体への強い参照を保持し、強い参照サイクルが発生してメモリリークが発生するため、が必要になりますblockSelf__weakブロックがヒープにコピーされていることを確認するcopyために必要です。新しいバージョンのコンパイラではこれは不要かもしれませんが、害はありません。

于 2013-06-21T12:33:53.530 に答える