0

作成したGCDキューに追加して(シリアルキューになります)、非同期で実行するメソッドがあります。そのコードブロック内からメインキューにディスパッチし、メインキューにディスパッチされたコードブロックが完了すると、BOOLフラグをYESに設定して、コードのさらに下の方でこの条件がYESかどうかを確認できるようにします。その後、次の方法に進むことができます。簡単に言うと、コードは次のとおりです。

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);

dispatch_async(queue, ^{

        Singleton *s = [Singleton sharedInstance];

        dispatch_sync(dispatch_get_main_queue(), ^{
            [s processWithCompletionBlock:^{

                // Process is complete
                processComplete = YES;
            }];
        });
});

while (!processComplete) {

        NSLog(@"Waiting");
}

NSLog(@"Ready for next step");

ただし、dispatch_syncはメインキューでコードを実行できないため、これは機能しません。これは、メインキューでwhileループを実行している(ビジー状態になっている)ためですか?

ただし、whileループの実装を次のように変更すると、次のようになります。

while (!processComplete) {

        NSLog(@"Waiting")
        NSDate *date = [NSDate distantFuture];
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
}

グリッチなしで動作します。これは、このシナリオで許容できるソリューションですか?他の好ましい方法でそれを行うことはできますか?どんな魔法がNSRunLoopやってるの?これをもっとよく理解する必要があります。

4

3 に答える 3

2

メイン スレッドの NSRunLoop ジョブの一部は、メイン スレッドでキューに入れられたブロックを実行することです。while ループでスピンすることにより、runloop の進行を妨げているため、明示的に自分でループを実行しない限り、キューに入れられたブロックは決して実行されません。

Runloops は Cocoa の基本的な部分であり、ドキュメントは非常に優れているため、一読することをお勧めします。

原則として、実行ループを手動で呼び出すことは避けます。複数の手動呼び出しを重ねて実行すると、メモリが無駄になり、物事が非常に複雑になります。

ただし、これを行うためのはるかに優れた方法があります。メソッドを -process と -didProcess メソッドに分割します。-process メソッドで非同期操作を開始し、完了したら、完了ブロックから -didProcess を呼び出します。あるメソッドから別のメソッドに変数を渡す必要がある場合は、それらを引数として -didProcess メソッドに渡すことができます。

例えば:

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);

dispatch_async(queue, ^{
        Singleton *s = [Singleton sharedInstance];

        dispatch_sync(dispatch_get_main_queue(), ^{
            [s processWithCompletionBlock:^{
                [self didProcess];
            }];
        });
});

また、シングルトンにディスパッチ キューを所有させ、dispatch_async の処理を​​担当させることを検討することもできます。これは、常に非同期で使用している場合、これらの厄介な埋め込みブロックをすべて節約できるためです。

例えば:

[[Singleton sharedInstance] processAyncWithCompletionBlock:^{
   NSLog(@"Ready for next step...");
   [self didProcess];
}];
于 2012-12-11T17:22:52.763 に答える
1

投稿したようなことをすると、UI がフリーズする可能性が高くなります。すべてを凍結するのではなく、完了ブロックで「次のステップ」のコードを呼び出します。

例:

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);
dispatch_queue_t main = dispatch_get_main_queue();

dispatch_async(queue, ^{

        Singleton *s = [Singleton sharedInstance];

        dispatch_async(dispatch_get_main_queue(), ^{
            [s processWithCompletionBlock:^{
                // Next step code
            }];
        });
});
于 2012-12-11T16:35:45.997 に答える
-2

ブロック内の値を待つようなループを作成しないでください。ブロック内の変数は読み取り専用であり、代わりにブロック内から完了コードを呼び出します。

dispatch_async(queue, ^{
    Singleton *s = [Singelton sharedInstance];
    [s processWithCompletionBlock:^{
        //process is complete
        dispatch_sync(dispatch_get_main_queue(), ^{
            //do something on main queue....
            NSLog(@"Ready for next step");
        });
    }];
});
NSLog(@"waiting");
于 2012-12-11T16:52:57.090 に答える