【问题标题】:Call completionHandler when two API calls have both completed?两个API调用都完成时调用completionHandler?
【发布时间】:2014-10-29 13:29:27
【问题描述】:

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

我有点不知道从哪里开始,我已经环顾四周,但我无法完全让 GCD 或 NSOperation 方法正常工作。该实例停留的时间足以让两个呼叫返回,但由于它们几乎同时返回,它们无法检查另一个是否已完成。我不知道如何检查,也不知道在哪里检查。

【问题讨论】:

  • 我相信我有你如此拼命寻找的代码??。给我一分钟找到它。

标签: ios concurrency grand-central-dispatch nsoperation


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您始终可以为调用这两个 API 请求的类设置一个计数器(整数属性或调用方法中的静态整数值),然后仅当计数器具有特定值时才执行返回块应该执行的任何操作增加/减少计数器并等待其他响应。这是一个糟糕的过程,但它是最省力的。

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

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

    这有很多可能性......我总是建议尝试制作它,以便您在类中至少有代码调用这组请求,而第一个过程正是这样做的。但话又说回来,如果您在很多情况下调用不同的请求集,那么最好创建一个更通用的系统,例如第二个和第三个过程中提到的。

    【讨论】:

      【解决方案3】:

      在没有delegates 的情况下,我能够做到这一点,所以不知道您对此有何感受,但这确实有效。我确实必须稍微调整代码,所以可能会出现一两个错误,因为可能某些变量不存在,因为我为这个答案删除了它们。

      如果我没有完全回答你想要的,或者如果你有任何问题,请发送电子邮件至 fabian.buentello@gmail.com

      类 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;
          }];
      }
      

      【讨论】:

        【解决方案4】:

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

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

        委托方法:在调度组上调用dispatch_group_leave。如何向代理提供调度组很大程度上取决于代码的工作方式。

        只有当对dispatch_group_enter 的调用次数等于对dispatch_group_leave 的调用次数时,您传递给dispatch_group_notify 的块才会被排入目标队列。在您调用dispatch_group_notify 时,您已经为每个请求调用了一次dispatch_group_enter,因此您需要为每个请求调用一次dispatch_group_leave,这将在请求返回其数据时触发。请注意,调度组并不关心您的请求返回的顺序,因为它看到的只是对dispatch_group_leave 的调用,没有额外的参数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-12
          • 1970-01-01
          • 2018-10-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多