Pregunta

Me pregunto si este marco de conectividad multipar está listo para usarse en el mundo real, dados todos los errores que ha encontrado la comunidad.Creo que lo estoy configurando correctamente, pero todos los demás proyectos de muestra que probé encuentran problemas similares.

El problema que tengo puede estar relacionado con algún problema inherente a Bonjour o algo así, no puedo entenderlo, pero básicamente el problema es el siguiente:

  • tengo un activo MCSession con varios compañeros.
  • Ahora, si un dispositivo está en una sesión, y luego la fuerza se retira, ese "Peer" permanece conectado por un período de tiempo indefinido.
  • No hay nada que pueda hacer para expulsar a ese usuario, aunque el browser:lostPeer: Se requiere un método para ese par y ya no aparece en el navegador como "cerca".
  • El session:peer:didChangeState: El método no se llama para ese par.
  • Cuando ese compañero que abandonó a la fuerza regresa a la aplicación, el usuario lo "encontrará" nuevamente. browser:foundPeer:withDiscoveryInfo: pero todavía existen en el session.connectedPeers NSArray.Obviamente, todavía no reciben ningún dato o actualización sobre la sesión y en realidad no están conectados.
  • Lo único que parece funcionar para registrar a ese par original como MCSessionStateNotConnected a la sesión es reconectando ese par a la sesión original.Luego hay una llamada duplicada a session:peer:didChangeState: donde está la nueva instancia del peerID MCSessionStateConnected y poco después la antigua instancia de las llamadas peerID con MCSessionStateNotConnected.

La aplicación de chat de muestra demuestra bien este problema: https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html

Dado que no parece haber ninguna forma de forzar manualmente la eliminación de un par de la sesión, ¿qué debo hacer?¿Debería intentar reconstruir la sesión de alguna manera?

Este Marco parece un poco desordenado, ¡pero estoy tratando de reservarme mi opinión!

¿Fue útil?

Solución

Mi única solución a este tipo de problema ha sido tener una relación 1-1 entre las sesiones y los pares.Complica el envío de transmisiones, pero al menos permite desconexiones y limpieza a nivel de pares desconectando/eliminando la sesión misma.

Actualizar

Para ampliar mi respuesta original, para poder enviar datos a pares conectados es necesario mantener una referencia a la sesión que se creó para cada par.He estado usando un diccionario mutable para esto.

Una vez enviada/aceptada la invitación con una nueva sesión, utilice el MCSession método delegado para actualizar el diccionario:

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {

    if (state==MCSessionStateConnected){

        _myPeerSessions[peerID.displayName] = session;

    }
    else if (state==MCSessionStateNotConnected){

        //This is where the session can be disconnected without
        //affecting other peers
        [session disconnect];            

        [_myPeerSessions removeObjectForKey:peerID.displayName];
    }
}

Se puede acceder a todos los pares con un método que devuelve todos los valores del diccionario y, a su vez, todos connectedPeers (en este caso uno) para cada MCSession:

- (NSArray *)allConnectedPeers {

   return [[_myPeerSessions allValues] valueForKey:@"connectedPeers"];

}

El envío de datos a un par en particular o mediante transmisión se puede realizar con un método como este:

- (void)sendData:(NSData *)data toPeerIDs:(NSArray *)remotePeers reliable:(BOOL)reliable error:(NSError *__autoreleasing *)error {

    MCSessionSendDataMode mode = (reliable) ? MCSessionSendDataReliable : MCSessionSendDataUnreliable;

    for (MCPeerID *peer in remotePeers){

       NSError __autoreleasing *currentError = nil;

       MCSession *session = _myPeerSessions[peer.displayName];
       [session sendData:data toPeers:session.connectedPeers withMode:mode error:currentError];

       if (currentError && !error)
        *error = *currentError;
    }
}

Otros consejos

¿Has probado a desconectar la sesión antes de que se cierre la aplicación?Esto debería eliminar al par de la sesión correctamente y limpiar cualquier recurso asignado al par.

Específicamente me refiero a algo como [self.peer disconnect] en applicationWillTerminate:

He estado teniendo problemas similares.Sin embargo, parece que si ejecuté mi aplicación en un dispositivo iOS y me conecté a otro, luego la salgo y la reinicio (por ejemplo, cuando vuelvo a ejecutar desde Xcode), entonces estoy en una situación en la que aparece un mensaje Conectado y luego un mensaje No conectado. mensaje un poco más tarde.Esto me estaba desconcertando.Pero mirando más detenidamente, puedo ver que el mensaje No conectado en realidad está destinado a un peerId diferente al que se ha conectado.

Creo que el problema aquí es que la mayoría de las muestras que he visto solo se preocupan por el nombre para mostrar del peerID y descuidan el hecho de que puede obtener múltiples peerID para el mismo dispositivo/nombre para mostrar.

Ahora estoy verificando primero el nombre para mostrar y luego verificando que el peerID sea el mismo, haciendo una comparación de los punteros.

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {

    MyPlayer *player = _players[peerID.displayName];

    if ((state == MCSessionStateNotConnected) &&
        (peerID != player.peerID)) {
        NSLog(@"remnant connection drop");
        return; // note that I don't care if player is nil, since I don't want to
                // add a dictionary object for a Not Connecting peer.
    }
    if (player == nil) {
        player = [MyPlayer init];
        player.peerID = peerID;
        _players[peerID.displayName] = player;
    }
    player.state = state;

...

No pude lograr que la respuesta aceptada funcionara, así que lo que hice fue tener un temporizador que se activaría para restablecer la conexión cuando el navegador informara que no estaba conectado y no había otros pares conectados.

-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{

//DebugLog(@"session didChangeState: %ld",state);

if(resetTimer != nil){
    [resetTimer invalidate];
    resetTimer = nil;
}

if(state == MCSessionStateNotConnected){

    [session disconnect];
    [peerSessions removeObjectForKey:peerID.displayName];
    [self removeGuidyPeerWithPeerID:peerID];
    //DebugLog(@"removing all guides from peer %@",peerID);

    if([localSession connectedPeers].count == 0){

        DebugLog(@"nothing found... maybe restart in 3 seconds");
        dispatch_async(dispatch_get_main_queue(), ^{
            resetTimer = [NSTimer
                      scheduledTimerWithTimeInterval:3.0
                      target:self selector:@selector(onResetTimer:)
                      userInfo:nil
                      repeats:NO];
            }
        );
    }
}
...

}

Puede eliminar el par de MCBrowserViewController con el siguiente código en Swift 3:

self.mySession.cancelConnectPeer(self.myPeerID)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top