7

スープの皆さん、

自分自身を呼び出す関数を実行しようとしていますが、すべてを 1 つのブロックに配置することで、

ご覧のように、次の関数は (arcrandom が 50 未満の数値を返すまで) 無制限に呼び出されることを意図しており、出力として、偶然に応じて可変数の "RUNNING" メッセージを期待する必要があります。

void (^_test_closure)(void) = ^ {
    NSLog(@"RUNNING");
    if(arc4random() % 100 > 50) {
        _test_closure();
    }
};

_test_closure();

ただし、実行すると EXC_BAD_ACCESS エラーが発生します。コードがクロージャー内で _test_closure を呼び出そうとすると、基本的にどこも指していないことがわかりました。

上記のコードを機能させる方法を知っている人はいますか?

4

3 に答える 3

8

ブロック自体をブロック変数として宣言する必要があります。

__block void (^_test_closure)();


_test_closure = ^{
    NSLog(@"Running...");
    if ((arc4random() % 100) > 50) {
        _test_closure();
    }
}

_test_closure();
于 2012-08-26T21:12:33.803 に答える
5

再帰とブロックはトリッキーです。ブロックは渡されたすべての変数をキャプチャするため、変数_test_closureはまだ初期化されていません (そして、clang は警告を表示するはずです:

ブロックによってキャプチャされると、ブロック ポインター変数 '_test_closure' が初期化されません。

)。

これを回避する方法はいくつかありますが、最も明白で最も簡単なのは、ブロック自体を__block変数にすることです (@H2CO3 が言ったこと)。これにより、ブロックをweak-linkedほぼそのままにすることができるため、再度呼び出したときに適切に初期化されます。

あなたが持っている別のオプションは、次のようにブロックをグローバルまたは静的にすることです:

// outside of 'main', thus being a global variable
void (^blockRecurse)(int) = ^(int level) {
    if (level < 0)
        return;
    NSLog(@"Level: %i", level);
    blockRecurse(--level);
};

int main()
{
    @autoreleasepool {
        blockRecurse(10);
    }
} 

これは、ブロックによってキャプチャされていないことを意味しますが、代わりに、すべてのコードで等しく変更できるグローバル/静的変数を参照しています。

于 2012-08-26T21:16:27.720 に答える