Подтвердить что ты не робот

Улучшенный асинхронный поток управления с блоками Objective-C

Я использую 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. Поскольку асинхронные вызовы могут иметь несколько результатов (успех/сбой) и не имеют возвращаемого значения, это не похоже на идеальное соответствие.

Любые указатели или идеи будут оценены.

4b9b3361

Ответ 1

Я еще не использовал его, но это звучит как Reactive Cocoa был разработан, чтобы делать то, что вы описываете.

Ответ 2

Я создал для этого легкое решение. Он назывался 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];

Ответ 3

Это было не редкость при использовании AFNetworking в Gowalla, чтобы иметь вызовы, объединенные вместе в блоки успеха.

Моим советом было бы включить сетевые запросы и сериализации, насколько это возможно, в методы класса в вашей модели. Затем для запросов, которые необходимо выполнить подзадачи, вы можете вызвать эти методы в блоке успеха.

Кроме того, если вы не используете его уже, AFHTTPClient значительно упрощает эти сложные сетевые взаимодействия.

Ответ 4

PromiseKit может оказаться полезным. Это, по-видимому, одна из наиболее популярных реализаций обещаний, а другие написали категории для интеграции с такими библиотеками, как AFNetworking, см. PromiseKit-AFNetworking.

Ответ 5

В 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!

Я еще не опробовал эту библиотеку, но она выглядит "многообещающей", несмотря на этот слегка подавляющий пример. (извините, я не удержался).