问题
你已添加好友到本地玩家账户,但现在想枚举这些好友并获得他们的信息,比如他们的别名。
解决方案
使用本地玩家对象的friends属性。
讨论
GKLocalPlayer有一个叫作friends的属性,为NSArray类型。该属性“将”包含本地玩家的好友;数组使用玩家ID(参考条目1.6)表示玩家。
上面的段落中说的是“将”,这是因为在本地玩家通过身份验证后,该数组是空的(nil)。你需要调用GKLocalPlayer类的实例方法loadFriendsWithCompletionHandler:来加载该数组。取得ID后,调用另外一个方法获取每个好友的其它信息。
GKLocalPlayer类的实例方法loadFriendsWithCompletionHandler:接受一个参数,该参数必须是一个返回void(换句话说,就是无返回值)并且拥有两个参数的块对象。块对象的第一个参数为NSArray类型,将返回本地玩家的好友ID。第二个参数为NSError类型,返回处理过程中是否有错误发生。
为避免代码多次重复,此处假定本地玩家已经通过身份验证(参考条目1.5)。
下面看看加载本地玩家好友ID的示例:
void (^getLocalPlayerFriends)(void) = ^{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
if ([localPlayer isAuthenticated] == NO){
NSLog(@"The local player is not authenticated.");
return;
}
NSLog(@"Loading local player's friend IDs...");
[localPlayer loadFriendsWithCompletionHandler:
^(NSArray *friends, NSError *error) {
if (friends != nil){
NSLog(@"Successfully retrieved friends of the local player.");
NSUInteger counter = 1;
for (NSString *friendID in friends){
NSLog(@"Friend %lu = %@", (unsigned long)counter, friendID);
counter++;
}
}
if (error != nil){
NSLog(@"Error occurred. Error = %@", error);
}
}];
};
如条目1.2中的第一步所提,我创建了三个游戏中心的玩家,这样才能向你演示游戏中心的功能。如果你仅创建了一个玩家,就无法去做诸如添加好友之类的事情,除非你能确切地知道沙盒上的其它玩家。不过,我再次强烈建议,你至少创建两位玩家,以便测试本书中的示例代码。
在iOS模拟器中运行该代码,获得类似如下的结果:
Loading local player's friend IDs...
Successfully retrieved friends of the local player.
Friend 1 = G:1428629254
Friend 1 = G:1428629742
如你所见,我添加了两位好友。如果你再次查看代码,就会注意到我检查了好友数组是否为nil,然后在then中检查加载过程中是否有错误发生。这么作的原因很简单:游戏中心只是试图加载本地玩家好友。即使有错误发生,也可能已经加载了一些信息。因此,你获得的数组中包含了本地玩家的部分好友。虽然只有好友的一部分,但你可能仍想继续执行下去。如果你要确定没有错误发生,我建议你首先检查错误参数,然后再打印数组friends的内容。
为侦测游戏中心是否能够成功加载好友列表,我们应当确保错误参数为nil;为侦测好友列表是否被部分接收,我们应当检查好友数组和错误参数是否都不是nil。如果有nil,则意味着,虽然我们可能获得了一些好友,但在获取其余好友时发生了错误。
一切都进行得不错,我拥有了本地玩家的好友的ID。为使用玩家ID取得GKPlayer类的实例,你得使用GKPlayer类的类方法loadPlayersForIdentifiers:withCompletionHandler:,完整的流程如下:
1. 验证本地玩家。
2. 获取本地玩家的ID。
3. 根据玩家ID获取GKPlayer的实例:
void (^getLocalPlayerFriendsDetails)(void) = ^{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
if ([localPlayer isAuthenticated] == NO){
NSLog(@"The local player is not authenticated.");
return;
}
if ([[localPlayer friends] count] == 0){
NSLog(@"The local player has no friends. How sad!");
return;
}
NSLog(@"Loading players...");
[GKPlayer
loadPlayersForIdentifiers:[localPlayer friends]
withCompletionHandler:^(NSArray *players, NSError *error) {
if (players != nil){
NSLog(@"Successfully loaded the players.");
for (GKPlayer *player in players){
NSLog(@"%@", player);
}
}
if (error != nil){
NSLog(@"Error happened. Error = %@", error);
}
}];
};
void (^getLocalPlayerFriends)(void) = ^{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
if ([localPlayer isAuthenticated] == NO){
NSLog(@"The local player is not authenticated.");
return;
}
NSLog(@"Loading local player's friend IDs...");
[localPlayer loadFriendsWithCompletionHandler:
^(NSArray *friends, NSError *error) {
if (friends != nil){
NSLog(@"Successfully retrieved friends of the local player.");
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, getLocalPlayerFriendsDetails);
}
if (error != nil){
NSLog(@"Error occurred. Error = %@", error);
}
}];
};
- (void) authenticateLocalPlayerAndGetHerInfo{
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^(void) {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
if ([localPlayer isAuthenticated] == NO){
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (error == nil){
NSLog(@"Successfully authenticated.");
dispatch_async(concurrentQueue, getLocalPlayerFriends);
} else {
NSLog(@"Failed to authenticate. Error = %@", error);
}
}];
} else {
dispatch_async(concurrentQueue, getLocalPlayerFriends);
}
});
}
调用authenticateLocalPlayerAndGetHerInfo之后,我获得了如下的信息(因为我通过身份验证的本地玩家,拥有两个好友):
Successfully authenticated.
Loading local player's friend IDs...
Successfully retrieved friends of the local player.
Loading players...
Successfully loaded the players.
<GKPlayer 0x5f32d90>(playerID: G:1428629254, alias: Test Game User 2,
status: (null), rid:(null))
<GKPlayer 0x5f32cf0>(playerID: G:1428629742, alias: Test Game User 3,
status: (null), rid:(null))
拥有这些信息后,你可以将他们显示给玩家或持有在以后引用。不要将玩家ID保存在游戏中。无论玩家何时运行你的应用程序,你都必须重新获取好友列表,而不要假设几天前获取的好友仍然是本地玩家的好友。另外,玩家ID的格式也可能改变,正如Apple在其文档中所提:
Do not make assumptions about the contents of the player identifier string. Its format and length are subject to change.