私のアプリはGKSessionModePeerでGKSessionを使用します。これは長い間実行されているアプリケーションで、ユーザーはバックグラウンドに戻り、後で戻ってくるはずだから、ピアを任意に接続したり切断したりする必要があります。ほとんどの場合、これはうまく動作します。しかし、ピアが切断すると、didChangeState:GKPeerStateDisconnectedは実際に切断されたデバイスだけでなく、実際にまだ接続されている他のデバイスに対しても、他のデバイスに通知されることがあります。GKSessionピアの切断により、他のピアが切断されて表示される
以下のコードと4つのデバイス(すべてiOS 5)でこの現象を再現できます。すべてが期待どおりになると、デバイスAは、アプリを終了したときに、他のすべてのデバイスに通知を取得し、それらのデバイス上のログ出力は次のようになります。
Service: didChangeState: peer A disconnected (12345)
しかし、しばらくした後、デバイスの接続を切断(例えば、再び)他のデバイスは、切断されなかったデバイスに対して追加のコールバックを取得します。例えば、デバイスCはなるだろう:
Service: didChangeState: peer A disconnected (...) // expected
Service: didChangeState: peer B disconnected (...) // never disconnected
を私は時々切断装置のログにメッセージのこれらの種類を見ています同じ頃、明確ではない、彼らは実際に関連している場合:
dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef
および/または
dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function
これが発生すると、GKSessionは不良状態にあるように見え、正しく接続や切断を処理しなくなります。良い状態に戻るためには、すべてのデバイスでアプリを強制終了し、少し待ってからやり直す必要があります。
バックグラウンドに移動するときにGKSessionを処理するさまざまな方法を試しました(利用可能な設定のみ=いいえ、切断しない、何もしない)。
他の誰かがこの動作に遭遇していますか(それを解決しましたか)?
AppDelegate(アークを使用して)でシンプルREPRO場合:
- (void)startGKSession
{
self.gkSession = [[GKSession alloc] initWithSessionID:nil displayName:nil sessionMode:GKSessionModePeer];
gkSession.disconnectTimeout = 10;
gkSession.delegate = self;
gkSession.available = YES;
}
- (void)shutdownGKSession
{
gkSession.available = NO;
[gkSession disconnectFromAllPeers];
gkSession.delegate = nil;
gkSession = nil;
[self.connectedDevices removeAllObjects];
}
- (void)connectToPeer:(NSString *)peerId
{
[gkSession connectToPeer:peerId withTimeout:10];
}
- (void)session:(GKSession *)session peer:(NSString *)peerId didChangeState:(GKPeerConnectionState)state
{
switch (state) {
case GKPeerStateAvailable:
NSLog(@"Service: didChangeState: peer %@ available, connecting (%@)", [session displayNameForPeer:peerId], peerId);
[self performSelector:@selector(connectToPeer:) withObject:peerId afterDelay:.5];
break;
case GKPeerStateUnavailable:
NSLog(@"Service: didChangeState: peer %@ unavailable (%@)", [session displayNameForPeer:peerId], peerId);
break;
case GKPeerStateConnected:
NSLog(@"Service: didChangeState: peer %@ connected (%@)", [session displayNameForPeer:peerId], peerId);
break;
case GKPeerStateDisconnected:
NSLog(@"Service: didChangeState: peer %@ disconnected (%@)", [session displayNameForPeer:peerId], peerId);
break;
case GKPeerStateConnecting:
NSLog(@"Service: didChangeState: peer %@ connecting (%@)", [session displayNameForPeer:peerId], peerId);
break;
}
}
- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID
{
[session acceptConnectionFromPeer:peerID error:nil];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.connectedDevices = [[NSMutableArray alloc] init];
[self startGKSession];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self shutdownGKSession];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self startGKSession];
}
@end