如何在显示UI之前等待Game Center匹配数据下载

时间:2014-05-27 12:51:25

标签: ios objective-c gkturnbasedmatch

我正在使用Game Center和GKTurnBasedMatch创建一个回合制游戏。

要在我的根控制器的表格视图中显示游戏列表,我正在调用以下方法:

-(void)reloadTableView
{    
    self.matchesTable.hidden = YES;
    [_activityIndicator startAnimating];

    [GKTurnBasedMatch loadMatchesWithCompletionHandler: ^(NSArray *matches, NSError *error)
     {
         if (error)
         {
             NSLog(@"loadMatchesWithCompletionHandler error:- %@", error.localizedDescription);

         } else
         {
             for (GKTurnBasedMatch *m in matches)
             {
                 // Download match data for each match
                 [m loadMatchDataWithCompletionHandler:^(NSData *matchData, NSError *error)
                  {
                      if (error)
                      {
                          NSLog(@"loadMatchDataWithCompletionHandler:- %@", error);

                      } else
                      {
                          [self processMatches]; // extracts match data to use in UI
                      }

                  }];

                 // Snipped - Code here to add each match to the relevant array ('My turn', 'Their turn' or 'Game over') for display in the table
             }

             [self.matchesTable reloadData];

             self.matchesTable.hidden = NO;
             [_activityIndicator stopAnimating];
        }
    }]; 
}

我希望任务顺序为:

1)隐藏matchesTable并启动活动指示器
2)致电loadMatchesWithCompletionHandler
3)对于每场比赛,请致电loadMatchDataWithCompletionHandler
4)在每场比赛中致电[self processMatches] 5)将每个匹配放入相关阵列中 6)停止活动指示器并显示matchesTable

然而,代码一直运行得如此之快以至于在任何匹配数据有时间下载之前执行了第6点,这意味着旧数据显示在我的表中。

所以我的一个大问题是:在继续使用其余方法之前,如何让程序等到每个匹配都下载了匹配数据? (即在第4点之后暂停,并且只有在每次匹配的匹配数据完成下载后才开始第5点)

1 个答案:

答案 0 :(得分:0)

由于您在loadMatchDataWithCompletionHandler的现有完成模块中添加了一个额外的完成功能块来循环调用loadMatchesWithCompletionHandler,因此它会启动加载匹配数据的调用等待他们的响应,然后它调用你的表重载方法,然后你的完成处理程序加载匹配数据开始触发(或在你的表重新加载的同时,没有真正的方法来指定你的代码)。

我建议使用GCD来取消您的请求。这样,您可以在dispatch_async中排队。如果可能,需要重新配置调用以获取匹配/数据。像这样:

self.matchesTable.hidden = YES;
[_activityIndicator startAnimating];

dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);
dispatch_async(myQueue, ^{
    NSError *error;
    NSArray *matches = [GKTurnBasedMatch loadMatches:&error];

    if(error)
        NSLog(@"Failed");
    else
    {
        for(GKTurnBasedMatch *m in matches)
        {
            // This will be on BG thread, but will ensure all calls are made before reloading table
            NSData *matchData = [m loadMatchData:&error];

            if(error)
                NSLog(@"Failed");
            else
                [self processMatches];

            // Snipped - Code here to add each match to the relevant array ('My turn', 'Their turn' or 'Game over') for display in the table
        }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.matchesTable reloadData];

        self.matchesTable.hidden = NO;
        [_activityIndicator stopAnimating];

    });
});

修改
根据您的意见,这种结构是不可能的。我想你可以做的其他事情就是知道需要进行的调用次数,并在每次调用完成时增加一些内容。如果您达到最大值,请进行更新。

...
int count = 0;
for (GKTurnBasedMatch *m in matches)
{
    // Download match data for each match
    [m loadMatchDataWithCompletionHandler:^(NSData *matchData, NSError *error)
     {
         count++;
         if (error)
         {
             NSLog(@"loadMatchDataWithCompletionHandler:- %@", error);
         } else
         {
             [self processMatches]; // extracts match data to use in UI
         }

         if(count == matches.count)
         {
             [self.matchesTable reloadData];

             self.matchesTable.hidden = NO;
             [_activityIndicator stopAnimating];
         }
     }];

    // Snipped - Code here to add each match to the relevant array ('My turn', 'Their turn' or 'Game over') for display in the table
}