我有一个包含3个步骤的过程。每个都需要在另一个之前完成(同步,串行等)。所有这些都需要在后台完成,以免阻止UI。
我正在尝试重新构建一些东西以使用2个队列,一个用于网络操作,一个用于数据库更新以保护核心数据。在队列之间来回反复,我可以保持连续,只需触发一个块,然后在完成后调用一些东西。
我正在使用addOperationWithBlock来创建操作并将其排队,但是没有看到完成块的明显方法(例如我使用setCompletionBlock)。我不确定如何完成第2步。我是否过度思考它,我只是在步骤1的块结束时调用下一个方法(步骤2的起点)?问题是这些块中的内容可能像AFNetworking调用一样异步。
这里有一些代码和更多信息。我想点击服务器,获取数据,然后在完成时执行其他操作,但链接它们以便它必须从数据到验证步骤顺序进行:
self.networkQueue = [NSOperationQueue new];
self.networkQueue.maxConcurrentOperationCount = 1;
self.databaseQueue = [NSOperationQueue new];
self.databaseQueue.maxConcurrentOperationCount = 1;
[self.networkQueue addOperationWithBlock:^{
NSString *listURL = [NSString stringWithFormat:GET_LIST,BASE_URL];
NSURL *url = [NSURL URLWithString:briefListURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.list = [NSArray arrayWithArray:(NSArray *)JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
[self listOperationDidFail];
}];
// define block that will execute when the task is finished
[operation setCompletionBlock:^{
// Latest data retrieved. Check if db needs updating
[self verifyList];
}];
[operation start];
}];
答案 0 :(得分:1)
使用您的代码会更容易回答,但您可以使用块内的嵌套调用以串行方式异步执行...
- (void)doThreeAsynchThingsSeriallyThenInvoke:(void (^)(void))finished {
[self doTheFirstThingThenInvoke:^(id result, NSError *error) {
if (!error) {
[self doTheSecondThingWith:result thenInvoke:^(BOOL success) {
[self doThLastThingThenInvoke:finished];
}];
}
}];
}
编辑 - 为了进一步说明,让我们说doTheFirstThing是关于进行网络调用然后解析结果:
- (void)doTheFirstThingThenInvoke:(void (^)(id, NSError *))finished {
NSURLRequest *request = // form a request, etc.
[NSURLConnection sendAsynchronousRequest:request queue:someQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
id parsed = nil;
if (!error) {
parsed = // parse the result contained in NSData *data
} else {
// handle error
}
// here's the important part: invoke the completion block either way
// it will get either nil and an error, or a parsed result and nil
finished(parsed, error);
}];
}
...让我们说doTheSecondThing用于在数据库中存储数据:
- (void)doTheSecondThingWith:(id)parsedData thenInvoke:(void (^)(BOOL))finished {
// you can do something asynch here, maybe on an operation queue
// or some other way off the main. Let's say it's an animation, because
// that takes a BOOL block and we can demonstrate just passing our
// block param along
[UIView animateWithDuration:3.0
animations:^{ self.someView.alpha = 0.0 }
completion:finished];
// see? we passed the finished block directly to the animation
// it will be invoked after the animation is complete
总之,第一件事(网络请求)发生了asynch,离开main,并在完成后调用了一个块。该块调用了第二个东西(动画),它将它的块传递给了一个aysnch操作。第三件事只会在网络请求和动画(两者都跑掉主要部分)完成后才会启动。
答案 1 :(得分:1)
这里真正的问题是队列中块的完成块中的异步过程。
这个食谱应该有所帮助:
创建NSOperationQueue的实例。设置maxConcurrentOperationCount = 1。
声明所有块进程及其完成块。放置你想要的任何东西。在每个块处理的开始处,放置一段代码来暂停创建的NSOperationQueue。在每个块的完成块结束时,放置一块取消挂起相同队列的代码 - 如果在块或其完成块中调用异步进程,则需要在该异步进程结束时放置/调用该未释放的代码。 / p>
将所有块添加到NSOperationQueue。
您还可以通过将每个流程嵌套在其他流程完成块中来完成工作。