Reconectarse con sus pares desconectados

Estoy usando el framework iOS 7 Multipeer en mi aplicación, pero estoy experimentando un problema con la desconnection de dispositivos. Si abro la aplicación en dos dispositivos: dispositivo A y dispositivo B, los dos dispositivos se conectan entre sí automáticamente. Sin embargo, después de varios segundos el dispositivo A se desconecta del dispositivo B. es decir, al principio la connection es así:

A ---> B A <--- B 

Luego de varios segundos:

 A ---> B AB 

El dispositivo A mantiene su connection pero el dispositivo B obtiene un MCSessionStateNotConnected.

Esto significa que A puede enviar datos a B, pero B no puede responder. Traté de evitar esto comprobando si el dispositivo está conectado y si no es así, reinicie la connection usando:

 [browser invitePeer:peerID toSession:_session withContext:Nil timeout:10]; 

Pero la callback didChangeState solo se llama con MCSessionStateNotConnected.

Extrañamente si envío la aplicación A al background, luego la vuelvo a abrir, B se vuelve a conectar y se mantiene la connection.

La API de Multipeer (y la documentation) parece un poco escasa, así que supuse que simplemente funcionaría. En esta situación, ¿cómo debería volver a conectar el dispositivo?

Estaba teniendo el mismo problema, y ​​parece que estaba relacionado con la navigation y la publicidad de mi aplicación al mismo time, y se enviaron / aceptaron dos invitaciones. Cuando dejé de hacer esto y dejo que un compañero deferencia al otro por las invitaciones, los dispositivos permanecieron conectados.

En el delegado de mi browser, estoy revisando el valor de hash de los pares descubiertos de los pares y enviando solo una invitación si mi compañero tiene un valor de hash más alto:

Editar

Como lo señaló @Masa, el valor de hash de un NSString será diferente en dispositivos de 32 y 64 bits, por lo que es más seguro usar el método compare: en displayName .

 - (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info { NSLog(@"Browser found peer ID %@",peerID.displayName); //displayName is created with [[NSUUID UUID] UUIDString] BOOL shouldInvite = ([_myPeerID.displayName compare:peerID.displayName]==NSOrdenetworkingDescending); if (shouldInvite) [browser invitePeer:peerID toSession:_session withContext:nil timeout:1.0]; else NSLog(@"Not inviting"); } 

Como usted dice, la documentation es escasa, así que quién sabe qué Apple realmente quiere que hagamos, pero he experimentado tanto enviar y aceptar invitaciones usando una sola session, como también crear una nueva session para cada invitación aceptada / enviada, pero esto Una manera particular de hacer las cosas me ha dado el mayor éxito.

Para cualquier persona interesada, creé MCSessionP2P , una aplicación de demostración que ilustra las funciones de networking ad hoc de MCSession . La aplicación se anuncia en la networking local y se conecta mediante progtwigción a los pares disponibles, estableciendo una networking peer-to-peer. Hat tip a @ChrisH por su técnica de comparación de valores hash para invitar a compañeros.

Me gustó la solución de ChrisH, que revela la idea key de que solo un compañero debe conectarse con el otro compañero , no ambos. Los bashs de connection mutua dan lugar a la desconnection mutua (aunque no es que una connection de un solo lado sea , contrariamente, una connection mutua en términos de estado y comunicación, por lo que funciona bien).

Sin embargo, creo que un enfoque mejor que el de un compañero es invitar a los pares a invitar pero solo a un compañero a aceptar . Uso este método ahora y funciona muy bien, porque ambos compañeros tienen la oportunidad de transmitir información enriquecida a la otra a través del parámetro de context de la invitación, en lugar de tener que contar con poca información disponible en el método de delegado foundPeer .

Por lo tanto, recomiendo una solución como esta:

 - (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info { [self invitePeer:peerID]; } - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL accept, MCSession *session))invitationHandler { NSDictionary *hugePackageOfInformation = [NSKeyedUnarchiver unarchiveObjectWithData:context]; BOOL shouldAccept = ([hugePackageOfInformation.UUID.UUIDString compare:self.user.UUID.UUIDString] == NSOrdenetworkingDescending); invitationHandler(shouldAccept && ![self isPeerConnected:peerID], [self openSession]); } 

Tengo el mismo problema cuando los dispositivos intentan conectarse entre sí al mismo time y no sé cómo encontrar un motivo porque no tenemos ningún error con MCSessionStateNotConnected .

Podemos usar alguna manera astuta para resolver este problema: coloque en los loggings de txt (información de descubrimiento) una hora [[date de date NS] timeIntervalSince1970] cuando se inició la aplicación. Quién comenzó primero: envíe invitación a otros.

Pero creo que no es una forma correcta (si las aplicaciones comienzan al mismo time, es poco probable … :)). Necesitamos averiguar la razón.

Este es el resultado de un error, que informé a Apple. Le expliqué cómo solucionarlo en mi respuesta a otra pregunta: ¿Por qué mi compañero de MCSession se desconecta random?

No he marcado estas preguntas para fusionar, porque mientras que el error y la solución subyacentes son iguales, las dos preguntas describen diferentes problemas.

Guarde el hash del par B. Utilizando un timer, verifique el estado de la connection continuamente si no está conectado intente volver a conectarse con cada período de time dado.

De acuerdo con el documento de Apple Elección de un invitador cuando se utiliza la conectividad de múltiples dispositivos "En iOS 7, el envío de invitaciones simultáneas puede provocar que ambas invitadas fallen, lo que hace que ambos no puedan comunicarse entre ellos".

Pero iOS 8 lo ha solucionado.