37

Web サービスへの非同期呼び出しにAFNetworkingを使用しています。これらの呼び出しの一部は連鎖する必要があり、呼び出し A の結果が呼び出し B で使用され、呼び出し C で使用されます。

AFNetworking は、操作の作成時に設定された成功/失敗ブロックを使用して、非同期呼び出しの結果を処理します。

NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/public_timeline.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
    NSLog(@"Public Timeline: %@", JSON);
} failure:nil];
[operation start];

これにより、ネストされた非同期呼び出しブロックがすぐに読み取れなくなります。タスクが相互に依存しておらず、代わりに並行して実行する必要があり、実行がすべての操作の結果に依存する場合は、さらに複雑になります。

promisesフレームワークを活用して制御フローをクリーンアップすることは、より良いアプローチのようです。

MAFuture に出会いましたが、 AFNetworkingと統合する最善の方法がわかりません。非同期呼び出しには複数の結果 (成功/失敗) があり、戻り値がない可能性があるため、理想的な適合とは思えません。

ポインタやアイデアをいただければ幸いです。

4

6 に答える 6

19

このための軽量ソリューションを作成しました。これは Sequencer と呼ばれ、githubにアップされています。

これにより、チェーン API 呼び出し (またはその他の非同期コード) を簡単かつ簡単に行うことができます。

AFNetworking を使用した例を次に示します。

Sequencer *sequencer = [[Sequencer alloc] init];

[sequencer enqueueStep:^(id result, SequencerCompletion completion) {
    NSURL *url = [NSURL URLWithString:@"https://alpha-api.app.net/stream/0/posts/stream/global"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        completion(JSON);
    } failure:nil];
    [operation start];
}];

[sequencer enqueueStep:^(NSDictionary *feed, SequencerCompletion completion) {
    NSArray *data = [feed objectForKey:@"data"];
    NSDictionary *lastFeedItem = [data lastObject];
    NSString *cononicalURL = [lastFeedItem objectForKey:@"canonical_url"];

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:cononicalURL]];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        completion(responseObject);
    } failure:nil];
    [operation start];
}];

[sequencer enqueueStep:^(NSData *htmlData, SequencerCompletion completion) {
    NSString *html = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
    NSLog(@"HTML Page: %@", html);
    completion(nil);
}];

[sequencer run];
于 2012-12-11T20:57:05.683 に答える
10

まだ使用していませんが、ReactiveCocoaはあなたが説明したとおりに動作するように設計されているようです。

于 2012-06-08T18:06:05.840 に答える
10

Gowalla で AFNetworking を使用している場合、呼び出しが成功ブロックに連鎖することは珍しくありませんでした。

私のアドバイスは、ネットワーク リクエストとシリアライゼーションを可能な限りモデルのクラス メソッドに組み込むことです。次に、サブリクエストを作成する必要があるリクエストについては、成功ブロックでそれらのメソッドを呼び出すことができます。

また、まだ使用していない場合は、AFHTTPClientこの種の複雑なネットワーク インタラクションが大幅に簡素化されます。

于 2012-06-11T15:05:45.320 に答える
6

PromiseKitが役立つ可能性があります。PromiseKit-AFNetworkingを参照してください。

于 2014-07-29T18:52:35.317 に答える
4

ここ Github には、CommonJS スタイルの promise の Objective-C 実装があります。

https://github.com/mproberts/objc-promise

例 (Readme.md から引用)

Deferred *russell = [Deferred deferred];
Promise *promise = [russell promise];

[promise then:^(NSString *hairType){
    NSLog(@"The present King of France is %@!", hairType);
}];

[russell resolve:@"bald"];

// The present King of France is bald!

私はまだこのライブラリを試していませんが、この少し圧倒される例にもかかわらず、「有望」に見えます。(申し訳ありませんが、私は抵抗できませんでした)。

于 2013-03-21T11:03:40.130 に答える