当两个API调用都完成时调用completionHandler?

时间:2014-10-29 13:29:28

标签: ios concurrency grand-central-dispatch nsoperation

在类的init方法中,我触发了两个通过委托响应的API调用。当两个调用都返回了它们的数据时,类本身需要发送一个完成处理程序。我已经尝试过使用GCD和一个调度组来实现这一目标,但我不完全确定我需要在代码中放置notify部分。委托方法(didReceiveData被调用两次,每次调用一次),可以是任何顺序等等,基本上我需要一种知道它们何时完成的方法,并返回它们的两组数据单个completionHandler。

我对从哪里开始感到有些困惑,我已经做了一些环顾四周,我不能完全使用GCD或NSOperation方法。实例持续了足够长的时间让两个调用回来,但由于他们几乎同时回来,他们无法检查对方是否已经完成。我不确定如何检查,我也不确定要检查的地方。

4 个答案:

答案 0 :(得分:0)

我使用NSNotifications完成了这项工作。基本上,当每个API请求完成时,发布NSNotification。添加NSNotification侦听器以管理每个通知触发时的跟踪状态。一旦侦听器收到两个通知,就可以调用completionHandler。

答案 1 :(得分:0)

你总是可以在调用这两个API请求的类中设置一个计数器(整数属性或调用方法中的静态整数值),然后只有在计数器具有某个值的情况下才能执行返回块应该执行的任何操作增加/减少计数器并等待其他响应。这是一个糟糕的程序,但它是最省力的。

如果你想以正确的方式做到这一点,有很多方法:

  • 您可以创建一个专门处理这两个请求的类,并将这两个响应作为属性包含在内。然后在响应块中设置目标响应属性并检查是否已设置其他响应,如果是,则调用输入块。
  • 您可以创建一个接收请求数组和回调块的类,然后使用内部计数器或只是保存响应。然后计算收到的每个响应的响应计数,看看你是否有足够的数量来调用输入回调块。
  • 你可以通过块创建一个系统,你传入一个可变字典,每个块应该设置一个特定的键(带有响应对象或状态代码或其他),然后在每个回调中检查字典中是否有足够的对象继续这个过程。

这有很多可能性...我总是建议尝试使它,所以你至少在类中调用这组请求的代码,第一个程序就是这样做的。但是如果你有很多情况下你会调用不同的请求集,那么最好再创建一个更通用的系统,如第二和第三个程序中提到的那样。

答案 2 :(得分:0)

我能够在没有delegates的情况下实现这一点,所以你对此感觉如何,但这确实有效。我确实需要稍微调整代码,因此可能会有一两个错误,因为可能有些变量不存在,因为我删除了它们以获得此答案。

如果我没有完全回答您的意见,或者如果您有任何疑问,请发送电子邮件至fabian.buentello@gmail.com

CLASS API

API.h

-(void)getMyDataWithCompletionHandler:(void (^)(NSMutableArray *firstData, NSMutableArray *secondData))Final_callBack;

API.m

-(void)getMyDataWithCompletionHandler:(void (^)(NSMutableArray *firstData, NSMutableArray *secondData))Final_callBack {

    NSString *firstURL = @"www.firstURL.com";
    NSString *secondURL = @"www.secondURL.com";

    __block bool firstIsBack = false;
    __block bool secondIsBack = false;

    __block NSMutableArray *firstArray = [NSMutableArray new];
    __block NSMutableArray *secondArray = [NSMutableArray new];

    [self getFirstData:firstURL
             withCallBack:^(NSMutableArray *firstData) {
              firstIsBack = true;
              firstArray = firstData;
                if (firstIsBack && secondIsBack){
                        Final_callBack(firstArray,secondArray);
                }      

              }
    }];

    [self getSecondData:secondURL
             withCallBack:^(NSMutableArray *secondData) {
              secondIsBack = true;
              secondArray = secondData;
                if (firstIsBack && secondIsBack){
                  Final_callBack(firstArray,secondArray);
                }      

              }
    }];    
}

<强>的viewController

@property (strong, nonatomic) NSMutableArray *finalFirstArray; @property (strong, nonatomic) NSMutableArray *finalSecondArray;

- (void)viewDidLoad{
    [super viewDidLoad];
    API *myApi = [API new];
    //make first call to 
    [myApi getMyDataWithCompletionHandler:^(NSMutableArray *firstData, NSMutableArray *secondData) {
         _finalFirstArray = firstData;
         _finalSecondArray = secondData;
    }];
}

答案 3 :(得分:0)

如果您使用的是调度组,则每次调用只需要担心自己的完成情况。总体思路如下:

初始化方法:从一个空的调度组开始(新创建,或者对dispatch_group_enterdispatch_group_leave进行平衡调用)。在进行每次API调用之前,请致电dispatch_group_enter。完成所有API调用后,请使用完成处理程序调用{​​{1}}。

委托方法:在调度组上调用dispatch_group_notify。如何向代表提供调度组主要取决于代码的工作方式。

传递给dispatch_group_leave的阻止只有在dispatch_group_notify的呼叫数等于dispatch_group_enter的呼叫数时才会加入目标队列。在您调用dispatch_group_leave时,您已为每个请求拨打了dispatch_group_enter,因此每个请求都需要一个dispatch_group_notify,当请求返回其数据时会触发。请注意,调度组不关心请求返回的顺序,因为它看到的只是对dispatch_group_leave的调用而没有其他参数。