为什么Social.localUser.Authenticate在Unity应用程序中没有互联网连接时会导致崩溃?

与互联网连接

一切都完美无瑕。 没有内存问题导致崩溃。

没有互联网连接

应用程序进入菜单屏幕,它最终崩溃,因为它是内存不足。

我得出的结论是,问题在于下面这行代码

Social.localUser.Authenticate 

当我注释掉上面这行时,当没有互联网连接时,内存问题就会消失。

这是我的相关代码

 void Start () { Social.localUser.Authenticate(ProcessAuthentication); } public void ProcessAuthentication(bool success) { if(success) Debug.Log ("Authenticated"); else Debug.Log ("Failed to authenticate"); } 

导致崩溃

 2016-02-27 15:46:37.131 BrickBall[449:60670] Received memory warning. WARNING -> applicationDidReceiveMemoryWarning() 2016-02-27 15:46:37.302 BrickBall[449:60670] Received memory warning. WARNING -> applicationDidReceiveMemoryWarning() 2016-02-27 15:46:37.349 BrickBall[449:60670] Received memory warning. WARNING -> applicationDidReceiveMemoryWarning() 2016-02-27 15:46:37.437 BrickBall[449:60670] Received memory warning. WARNING -> applicationDidReceiveMemoryWarning() Message from debugger: Terminated due to memory issue 

为什么在没有互联网连接的情况下,这行代码会导致内存不足?

我的猜测是,你最终需要和Unity交谈。 游戏中心将在没有networking连接的情况下使用caching的凭据,报告它已成功连接到服务器并进行身份validation,即使没有。 我在这方面有一个问题,就是苹果公司正在进行一场讨论。 这种行为允许一些游戏types即使在没有networking的情况下也可以继续,然后在连接恢复时同步。 然而,我遇到了问题,我认为我可以做的事情,因为GC说,它是authentication,但我真的不能,因为它不是真的。 :/

这意味着应用程序必须处理三种情况:

  • 使用GC成功validation
  • GCvalidation失败
  • 身份validation失败,但基于caching的数据报告为成功

Unity可能不处理第三种情况。 要确认或反驳,请尝试以下操作:

确认Unity干净地处理authentication失败

  1. build立连接

  2. 退出游戏中心

  3. 断开连接(飞行模式等)

  4. 重试您的应用程序

我认为在这一点上success是错误的,并且干净利落。

如果这种方式如预期的那样,我会和Unity谈谈他们如何处理Game Center在断开连接的情况下报告(caching)的成功。

EDIT2:

我不得不回过头来看看我的代码,看看我是如何硬着头皮的。 情况是:在完全断开连接和/或在飞行模式下,Game Center呈现“欢迎回来”消息,并且localPlayer.authenticated被设置为YES …但是,错误代码被设置并且抱怨它不能连接。

我打开了错误22232706,“[GKLocalPlayer localPlayer] .authenticated在任何身份validation处理程序设置后总是返回true”,而且还有一个正在进行的讨论。 苹果证实了这一行为,但表示其意图。

以下是我如何加强我的身份validation处理程序来处理这种情况。 由于Unity正在为您处理这个问题,所以这不会对您有所帮助,但是我认为其他读者可能会觉得这很有帮助。 (TL; DR版本是:在检查.authenticated之前或者在检查viewController是否设置之前, 总是 总是先检查错误代码)

 [localPlayer setAuthenticateHandler:^(UIViewController *loginViewController, NSError *error) { //Note: this handler fires once when you call setAuthenticated, and again when the user completes the login screen (if necessary) //did we get an error? Could be the result of either the initial call, or the result of the login attempt //Very important: ALWAYS check `error` before checking for a viewController or .authenticated. if (error) { //Here's a fun fact... even if you're in airplane mode and can't communicate to the server, //when this call back fires with an error code, localPlayer.authenticated is sometimes set to YES despite the total failure. >< //combos seen so far: //error.code == -1009 -> authenticated = YES //error.code == 2 -> authenticated = NO //error.code ==3 -> authenticated = YES if ([GKLocalPlayer localPlayer].authenticated == YES) { NSLog(@"error.code = %ld but localPlayer.authenticated = %d", (long)error.code, [GKLocalPlayer localPlayer].authenticated); } //Do stuff here to disable network play, disable buttons, warn users, etc. return; } //if we received a loginViewContoller, then the user needs to log in. if (loginViewController) { //the user isn't logged in, so show the login screen. [rootVC2 presentViewController:loginViewController animated:NO completion:^ { //was the login successful? if ([GKLocalPlayer localPlayer].authenticated) { //enable network play, or refresh matches or whatever you need to do... } }]; } //if there was not loginViewController and no error, then the user is alreay logged in else { //the user is already logged in //refresh matches, leaderboards, whatever you need to do... } }];