Ответ 1
Я еще не использовал его, но это звучит как Reactive Cocoa был разработан, чтобы делать то, что вы описываете.
Я использую 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. Поскольку асинхронные вызовы могут иметь несколько результатов (успех/сбой) и не имеют возвращаемого значения, это не похоже на идеальное соответствие.
Любые указатели или идеи будут оценены.
Я еще не использовал его, но это звучит как Reactive Cocoa был разработан, чтобы делать то, что вы описываете.
Я создал для этого легкое решение. Он назывался 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];
Это было не редкость при использовании AFNetworking в Gowalla, чтобы иметь вызовы, объединенные вместе в блоки успеха.
Моим советом было бы включить сетевые запросы и сериализации, насколько это возможно, в методы класса в вашей модели. Затем для запросов, которые необходимо выполнить подзадачи, вы можете вызвать эти методы в блоке успеха.
Кроме того, если вы не используете его уже, AFHTTPClient
значительно упрощает эти сложные сетевые взаимодействия.
PromiseKit может оказаться полезным. Это, по-видимому, одна из наиболее популярных реализаций обещаний, а другие написали категории для интеграции с такими библиотеками, как AFNetworking, см. PromiseKit-AFNetworking.
В Github существует Objective-C реализация стиля CommonJS promises:
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!
Я еще не опробовал эту библиотеку, но она выглядит "многообещающей", несмотря на этот слегка подавляющий пример. (извините, я не удержался).