私は現在、多くの複雑な非同期パターンを非常に簡単に実装できるようにするライブラリ (ソースが GitHub にある RXPromise) を開発しています。
次のアプローチでは、クラスRXPromise
を利用し、100% 非同期のコードを生成します。つまり、ブロックはまったくありません。「待機」は、非同期タスクが終了またはキャンセルされたときに呼び出されるハンドラーによって実現されます。
また、ライブラリの一部ではないカテゴリも使用しますがNSArray
、RXPromise ライブラリを使用して簡単に実装できます。
たとえば、コードは次のようになります。
- (RXPromise*)asyncTestAbc
{
return [someThing retrieve:@"foo"]
.then(^id(id unused /*names?*/) {
// retrieve:@"foo" finished with success, now execute this on private queue:
NSArray* names = @[@"John", @"Mary", @"Peter", @"Madalena"];
return [names rx_serialForEach:^RXPromise* (id name) { /* return eventual result when array finished */
return [someObject lookupName:name] /* return eventual result of lookup's completion handler */
.thenOn(mainQueue, ^id(id result) {
assert(<we are on main thread>);
// A. Do something after a lookupName:name completes a few seconds later
return nil;
}, nil /*might be implemented to detect a cancellation and "backward" it to the lookup task */);
}]
},nil);
}
最終結果をテストするには:
[self asyncTestAbc]
.thenOn(mainQueue, ^id(id result) {
// C. all `[someObject lookupName:name]` and all the completion handlers for
// lookupName, and `[someThing retrieve:@"foo"]` have finished.
assert(<we are on main thread>);
STAssertTrue(...);
}, id(NSError* error) {
assert(<we are on main thread>);
STFail(@"ERROR: %@", error);
});
メソッドは、非同期asyncTestABC
であることを除いて、説明したことを正確に実行します。テスト目的で、完了するまで待つことができます。
[[self asyncTestAbc].thenOn(...) wait];
ただし、メインスレッドで待機しないでください。そうしないとasyncTestAbc
、メインスレッドでも完了ハンドラーが呼び出されるため、デッドロックが発生します。
これが役立つと思われる場合は、より詳細な説明をリクエストしてください。
注: RXPromise ライブラリはまだ「作業中」です。複雑な非同期パターンを扱うすべての人に役立つかもしれません。上記のコードは、現在 GitHub でマスターにコミットされていない機能を使用しています:thenOn
ハンドラーが実行されるキューを指定できるプロパティ。現在then
、ハンドラーが実行されるパラメーター キューを省略したプロパティのみがあります。特に指定しない限り、すべてのハンドラーは共有プライベート キューで実行されます。提案は大歓迎です!