在我的应用程序中,我正在尝试将GameCenter播放器ID转换为其别名。收到ID后,我从循环中调用以下方法。该方法一次调用一个id,并应返回单个别名。我只是想返回一个别名,但无法让它工作。起初我把回程放在块中,但我发现你不能回到它里面。现在我设置它所以它将对象添加到数组并在块之后返回但是它给出了以下错误:[__ NSArrayM objectAtIndex:]:索引0超出空数组的边界'。任何帮助将不胜感激。
@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];
}
答案 0 :(得分:0)
loadPlayersForIdentifiers: withCompletionHandler:
异步加载玩家,因此完成处理程序。在[_playerScores objectAtIndex:0]
时,尚未调用完成处理程序且playerScores
为空。这就是你看到错误的原因。
对于任何解决方案,您必须接受异步是异步的。对于一个非常简单的解决方案,您可以让loadPlayerData:
不返回任何内容(void
)。 _playerScores
已经看起来像一个成员变量,您可以在以后重复检查它。
编辑:引用明确指出在主线程上调用了完成处理程序:
稍后,当任务完成时,Game Kit会调用您的完成处理程序。始终在主线程上调用完成处理程序。
这很好,因为那样你就可以在加载别名的完成处理程序中安全地调用[self.tableView reloadData];
。但是,根据您的修改,还有两个问题变得清晰:
在for
的完成处理程序中的scores
- loadScoresWithCompletionHandler:
循环中,您反复为您传递给{{的玩家ID实例化数组player
1}}。首先填充此数组会更好,然后立即调用loadPlayerData:
所有玩家ID。
即使您调用loadPlayerData:
,[self.tableView reloadData]
也尚未完成其工作,因为loadPlayerData:
异步工作。
为了快速解决问题,我可能希望简化查询播放器别名的方式,并在播放器别名从Game Center服务器到达后更新您的表格视图。
loadPlayersForIdentifiers:
我遗漏了你对实际分数的处理,以便更明确地说明问题。现在你只加载一次播放器别名(有多个排行榜是你可能需要另外解决的另一个问题)。
[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];
}];
}
字典查找玩家ID的昵称。由于您在加载分数的完成处理程序中调用_playerAliases
,所有数据将在loadPlayerData:
完成后准备就绪。因此,这是一个方便的时间来触发表视图的更新。
答案 1 :(得分:0)
请使用此演示版集成游戏中心 https://github.com/nihalahmed/GameCenterManager
答案 2 :(得分: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);
}
}
}];