使用Objective-C块实现更好的异步控制流程

bro*_*nko 37 design-patterns objective-c objective-c-blocks afnetworking

我正在使用AFNetworking来异步调用Web服务.这些呼叫中的一些必须链接在一起,其中呼叫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];
Run Code Online (Sandbox Code Playgroud)

这会导致嵌套的异步调用块很快变得不可读.当任务不依赖于彼此而是必须并行执行并且执行取决于所有操作的结果时,它甚至更复杂.

似乎更好的方法是利用promises框架来清理控制流.

我遇到过MAFuture,但无法弄清楚如何最好地将它与AFNetworking集成.由于异步调用可能有多个结果(成功/失败)并且没有返回值,因此它似乎不是理想的选择.

任何指针或想法将不胜感激.

Tal*_*key 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];
Run Code Online (Sandbox Code Playgroud)


Jon*_*eid 10

我还没有用它,但听起来Reactive Cocoa的设计就是为了你所描述的.


mat*_*ttt 10

在Gowalla中使用AFNetworking在成功阻止中将呼叫链接在一起并不罕见.

我的建议是尽可能地将网络请求和序列化分解为模型中的类方法.然后,对于需要进行子请求的请求,您可以在成功块中调用这些方法.

此外,如果您尚未使用它,则可以AFHTTPClient极大地简化这些复杂的网络交互.


jef*_*max 6

PromiseKit可能很有用.它似乎是更受欢迎的承诺实现之一,而其他人已经编写了类别以将其与AFNetworking等库集成,请参阅PromiseKit-AFNetworking.