Question

Je me demande si ce framework Multipeer Connectivity est prêt à être utilisé dans le monde réel, compte tenu de tous les bugs rencontrés par la communauté.Je pense que je le configure correctement, mais tous les autres exemples de projets que j'ai essayés rencontrent des problèmes similaires.

Le problème que je rencontre est peut-être lié à un problème inhérent à Bonjour ou quelque chose du genre, je n'arrive pas à le comprendre, mais en gros, le problème est le suivant :

  • J'ai un actif MCSession avec un certain nombre de pairs.
  • Maintenant, si un appareil est en session, et alors force à quitter, ce "Peer" reste connecté pendant une durée indéfinie.
  • Je ne peux rien faire pour forcer cet utilisateur à quitter, même si le browser:lostPeer: La méthode est appelée pour ce pair et ne se présente même plus dans le navigateur comme "à proximité".
  • Le session:peer:didChangeState: la méthode n’est pas appelée pour cet homologue.
  • Lorsque ce pair qui a été forcé de quitter revient à l'application, il est à nouveau « trouvé » par le browser:foundPeer:withDiscoveryInfo: mais existent toujours aussi dans le session.connectedPeers NSArray.Évidemment, ils ne reçoivent toujours aucune donnée ou mise à jour sur la session et ne sont pas réellement connectés.
  • La seule chose qui semble fonctionner pour enregistrer cet homologue d'origine en tant que MCSessionStateNotConnected à la session consiste à reconnecter ce homologue à la session d'origine.Ensuite, il y a un appel en double à session:peer:didChangeState: où se trouve la nouvelle instance du peerID MCSessionStateConnected et peu de temps après l'ancienne instance des appels peerID avec MCSessionStateNotConnected.

L’exemple d’application de chat illustre bien ce problème : https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html

Puisqu'il ne semble pas y avoir de moyen de forcer manuellement la suppression d'un homologue de la session, que dois-je faire ?Dois-je essayer de reconstruire la session d'une manière ou d'une autre ?

Ce cadre semble un peu compliqué, mais j'essaie de réserver mon jugement !

Était-ce utile?

La solution

Ma seule solution à ce type de problème a été d'avoir une relation 1-1 entre les sessions et les pairs.Cela complique l'envoi de diffusions, mais permet au moins des déconnexions et un nettoyage au niveau des pairs en déconnectant/supprimant la session elle-même.

Mise à jour

Pour développer ma réponse originale, afin de pouvoir envoyer des données aux pairs connectés, il est nécessaire de conserver une référence à la session créée pour chaque pair.J'utilise un dictionnaire mutable pour cela.

Une fois l'invitation envoyée/acceptée avec une nouvelle session, utilisez le MCSession méthode déléguée pour mettre à jour le dictionnaire :

- (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];
    }
}

Tous les pairs sont accessibles avec une méthode qui renvoie toutes les valeurs du dictionnaire, et à leur tour toutes les valeurs du dictionnaire. connectedPeers (dans ce cas un) pour chacun MCSession:

- (NSArray *)allConnectedPeers {

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

}

L'envoi de données à un homologue particulier ou via diffusion peut être effectué avec une méthode comme celle-ci :

- (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;
    }
}

Autres conseils

Avez-vous essayé de déconnecter la session avant la fermeture de l'application ?Cela devrait supprimer correctement le homologue de la session et nettoyer toutes les ressources allouées au homologue.

Plus précisément, je veux dire quelque chose comme [self.peer disconnect] dans applicationWillTerminate:

J'ai eu des problèmes similaires.Il semble cependant que si j'ai exécuté mon application sur un appareil iOS et que je me suis connecté à un autre, puis que je l'ai quitté et relancé (par exemple, lorsque je réexécute depuis Xcode), je me trouve dans une situation où je reçois un message Connecté, puis un message Non connecté. message un peu plus tard.Cela me déstabilisait.Mais en regardant plus attentivement, je peux voir que le message Not Connected est en fait destiné à un peerId différent de celui qui s'est connecté.

Je pense que le problème ici est que la plupart des exemples que j'ai vus se soucient uniquement du displayName du peerID et négligent le fait que vous pouvez obtenir plusieurs peerID pour le même périphérique/displayName.

Je vérifie maintenant d'abord le displayName, puis je vérifie que le peerID est le même, en effectuant une comparaison des pointeurs.

- (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;

...

Je n'ai pas pu obtenir que la réponse acceptée fonctionne, donc ce que j'ai fait à la place, c'est d'avoir une minuterie qui se déclencherait pour réinitialiser la connexion lorsque le navigateur signalerait qu'il n'est pas connecté et qu'il n'y avait aucun autre homologue connecté.

-(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];
            }
        );
    }
}
...

}

Vous pouvez supprimer le homologue du MCBrowserViewController avec le code suivant dans Swift 3 :

self.mySession.cancelConnectPeer(self.myPeerID)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top