1

在我的应用程序中,我试图将 GameCenter 玩家 ID 转换为他们的别名。收到 ID 后,我会从循环中调用以下方法。该方法一次使用一个 id 调用,并且应该返回一个别名。我只是想返回一个别名,但无法让它工作。起初我把退货放在块里,但我发现你不能在里面退货。现在我已经设置好了,所以它将对象添加到数组并在块之后返回,但是它给了我以下错误:[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'。任何帮助将不胜感激。

@property (nonatomic, strong, retain) NSMutableArray * playerScores;

.

-(void)getScoresAndAliasForLeaderboard{
 [GKLeaderboard loadLeaderboardsWithCompletionHandler:^(NSArray *leaderboards, NSError *nsError) {
        if( nsError != nil )
        {
            //error( nsError, "get leaderboard score" ) ;
            return ;
        }

        for( GKLeaderboard* board in leaderboards )
        {
            board.timeScope = GKLeaderboardTimeScopeAllTime;
            board.playerScope = GKLeaderboardPlayerScopeGlobal;
            board.range = NSMakeRange(1, 100);

            [board loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
                 NSLog(@"board: %@",board.description);

                NSLog(@"error: %@",error);
                if (error == nil)
                {
                    for (GKScore *s in scores)
                    {

                        GCLeaderboardScore *playerScore = [[GCLeaderboardScore alloc] init];
                        playerScore.playerID = s.playerID;
                        playerScore.score = (int)s.value;
                        playerScore.rank = s.rank;
                        NSArray * player = [[NSArray alloc]initWithObjects:s.playerID, nil];
                        [self loadPlayerData:player];
                        playerScore.alias = [_playerScores objectAtIndex:0];
                        NSLog(@"alias: %@, score: %d",playerScore.alias ,playerScore.score);
                        [_dataMutableArray addObject: playerScore];
                    }
                    [self.tableView reloadData];
                }
            }];


        }
                }] ;

}

.

-(NSString*) loadPlayerData: (NSArray *) identifiers
{
    if(!_playerScores){
    _playerScores = [[NSMutableArray alloc]init];
    }
    [GKPlayer loadPlayersForIdentifiers:identifiers withCompletionHandler:^(NSArray *players, NSError *error)
     {

         if (error != nil)
         {
             // Handle the error.
         }
         if (players != nil)
         {
                 GKPlayer* player = [players objectAtIndex:0];
                 [_playerScores addObject:player.alias];
         }
     }];

    return [_playerScores objectAtIndex:0];
}
4

3 回答 3

0

loadPlayersForIdentifiers: withCompletionHandler:异步加载播放器,因此是完成处理程序。当时你[_playerScores objectAtIndex:0]还没有调用完成处理程序并且playerScores是空的。这就是您看到错误的原因。

对于任何解决方案,您都必须接受异步就是异步的。对于一个非常简单的解决方案,您可以loadPlayerData:不返回任何内容 ( void)。_playerScores已经看起来像一个成员变量,您可以在以后反复检查它。

编辑:参考明确指出在主线程上调用完成处理程序:

稍后,当任务完成时,Game Kit 会调用您的完成处理程序。完成处理程序总是在主线程上调用。

这很好,因为这样您就可以安全地[self.tableView reloadData];从加载别名的完成处理程序中调用。但是,根据您的编辑,还有两个问题变得清晰:

  1. 在您的完成处理程序的for循环中重复实例化您传递给的玩家 ID的数组。最好先填充这个数组,然后一次调用所有玩家 ID。scoresloadScoresWithCompletionHandler:playerloadPlayerData:loadPlayerData:

  2. 即使您调用[self.tableView reloadData]loadPlayerData:也不会完成它的工作,因为它loadPlayersForIdentifiers:是异步工​​作的。

为了快速修复,我可能希望简化查询玩家别名的方式,并仅在玩家别名从 Game Center 服务器到达后才更新表视图。

[board loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error) {
    if (error)
    {
        return;
    }
    NSArray *player_ids = [[NSMutableArray alloc] init];
    for (GKScore *s in scores)
    {
        [player addObject:s.playerID];
    }
    [self loadPlayerData:player];
}];

我省略了您对实际分数的处理,以使这一点更清楚。现在您只需加载玩家别名一次(拥有多个排行榜是您可能需要单独解决的另一个问题)。

-(void)loadPlayerData:(NSArray *)identifiers
{
    if (! _playerAliases) {
        _playerAliases = [[NSMutableDictionary alloc]init];
    }
    [GKPlayer loadPlayersForIdentifiers:identifiers
        withCompletionHandler:^(NSArray *players, NSError *error)
    {
        if ((error) || (! players))
        {
            return;
        }
        for (GKPlayer p in players)
        {
            [_playerAliases setObject:player.alias forKey::player.id];
        }
        [self.tableView reloadData];
    }];
}

现在您可以使用_playerAliases字典来查找玩家 ID 的昵称。由于您从加载分数的完成处理程序中调用loadPlayerData:,所有数据在完成后准备好loadPlayersForIdentifiers:。因此,这是触发表视图更新的方便时机。

于 2013-11-09T19:31:04.643 回答
0

请将此演示用于集成游戏中心 https://github.com/nihalahmed/GameCenterManager

于 2014-06-11T14:23:46.047 回答
0

你好!这个对我有用。

这是我的代码:

GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];

leaderboardRequest.identifier = kHighScoreLeaderboardCategory;



[leaderboardRequest loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error)

 {

if (error) {




NSLog(@"%@", error);
        } 

else if (scores) 
{

        for (GKScore *s in scores)

        {
            NSLog(@"Local player name is : %@", s.player.alias);

             NSLog(@"Local player score's: %@", s.formattedValue);


        }

    }
}];
于 2015-01-06T10:28:07.497 回答