4

だからここに私が持っているものがあります:

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), ^{
                bool ready = some_function();
                if( ready ) {                    
                   do_smth_here()
                } else {
                   //invoke this block one more time after 0.1 sec
                }
            });

問題は、現在のブロックへの参照を取得する方法です。

4

3 に答える 3

4

上に示したフープを飛び越える代わりに、私は通常、必要に応じて内部的に再トリガーを処理する、呼び出すことができるインスタンスメソッドを宣言します。このように、任意のブロックはワンショットですが、再トリガーによって新しいブロックが作成されます。

ブロックの作成にそれほど費用がかからない限り(インスタンスメソッドをカプセル化したものから状態が発生している場合はそうではありません)、十分に効率的であり、非常に簡単です。

- (void) retriggerMethod
{
     ... do stuff here, assuming you want to do it on first invocation ...
     dispatch_after( ..., ^{
         [self retriggerMethod];
     });
}

必要に応じて再構築できます。また、同時再トリガーなどから保護したい場合は、BOOLインスタンス変数を簡単に追加できます...

これは、キャンセルするための便利なフックも提供します。次の呼び出しで実際に何かを実行して再スケジュールする必要があるかどうかを示すBOOLをインスタンスに追加するだけです。

于 2012-06-12T21:49:14.320 に答える
3

Jeffrey Thomas の答えは近いですが、ARC の下ではブロックがリークし、ARC がないとクラッシュします。

ARC がないと、__block変数はそれが参照するものを保持しません。ブロックはスタック上に作成されます。したがって、callback変数はスタック上のブロックを指します。初回(ブロック外)に渡すcallbackと、正常にヒープ上にブロックのコピーが作成されます。しかし、そのコピーが呼び出されて再び渡されると、(スタック上の現在破棄されているブロックへの) ぶら下がっているポインターになり、(通常は) クラッシュします。dispatch_afterdispatch_aftercallbackdispatch_aftercallbackdispatch_after

ARC では、__blockブロック型の変数 ( などcallback)はブロックを自動的にヒープにコピーします。したがって、クラッシュすることはありません。しかし、ARC では、__block変数はそれが参照するオブジェクト (またはブロック) を保持します。これにより、保持サイクルが発生します。つまり、ブロック自体が参照されます。dispatch_afterXcode は再帰呼び出しに関する警告を表示します。

これらの問題を修正するには、ブロックを明示的にコピーして (スタックから MRC の下のヒープに移動するため)、callbacknil に設定する (ARC の下で) か、ブロックを解放して (MRC の下で) リークを防ぐことができます。

    __block void (^callback)() = [^{
        if(stop_) {
            NSLog(@"all done");
#if __has_feature(objc_arc)
            callback = nil; // break retain cycle
#else
            [callback release];
#endif
        } else {
            NSLog(@"still going");
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
        }
    } copy];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);

明らかに#if、メモリ管理に適したブランチを削除して使用することができます。

于 2012-06-12T20:12:31.313 に答える
1

これがあなたが探しているコードだと思います:

__block void (^callback)();
callback = ^{
    bool ready = some_function();
    if( ready ) {
        do_smth_here()
    } else {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
    }
};

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);

^ブロックのヒントとコツに感謝

于 2012-06-12T16:17:46.300 に答える