2014-04-11 9 views
13

Mi chiedo se questo framework Multipeer Connectivity sia pronto per l'uso nel mondo reale, dati tutti i bug che sono stati riscontrati dalla comunità. Penso che sto configurando correttamente, ma tutti gli altri progetti di esempio che ho provato incontrano problemi simili.Multipeer Connectivity Framework - Lost Peer rimane in sessione

Il problema che sto avendo possono essere legati a qualche problema inerente Bonjour o qualcosa, non riesco a capire, ma fondamentalmente il problema è il seguente:

  • Ho un attivo MCSession con un certo numero di colleghi.
  • Ora, se un dispositivo è in una sessione e quindi si chiude forzatamente, quel "peer" rimane connesso per un periodo di tempo indefinito.
  • Non c'è nulla che io possa fare per forzare quell'utente, anche se il metodo browser:lostPeer: viene chiamato per quel peer e non viene più visualizzato nel browser come "Nelle vicinanze".
  • Il metodo session:peer:didChangeState: non viene chiamato per quel peer.
  • Quando quel peer che forza abbandonata ritorna all'app, sono nuovamente "Trovato" dallo browser:foundPeer:withDiscoveryInfo: ma esistono ancora anche nel filtro NSArray session.connectedPeers. Ovviamente non ricevono alcun dato o aggiornamento sulla sessione e non sono effettivamente connessi.
  • L'unica cosa che sembra funzionare per registrare quel peer originale come MCSessionStateNotConnected per la sessione è ricollegando quel peer alla sessione originale. Quindi c'è una chiamata duplicata a session:peer:didChangeState: dove la nuova istanza del peerID è MCSessionStateConnected e poco dopo la precedente istanza delle chiamate peerID con MCSessionStateNotConnected.

L'applicazione di chat esempio illustra questo problema così: https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html

Dal momento non sembra essere un modo per forzare rimuovere manualmente un pari dalla sessione, cosa devo fare? Dovrei provare e ricostruire la sessione in qualche modo?

Questo quadro sembra un po 'un disastro, ma sto cercando di esprimere un giudizio!

+0

ho avuto una domanda di lavoro, ma necessaria per estenderla oltre 8 coetanei, ora il suo rotto :(ho. trovato un problema finora, non inavvertitamente avere forti riferimenti agli oggetti MC quando si passa in background (lo so, si applica più ampiamente di MC .. ma un promemoria aiuta!) – 300baud

+0

Ho lo stesso problema. A volte la sessione di MCSession: peer : didChangeState: non verrà chiamato con MCSessionStateNotConnected per un peer che ha disconnessione. Quando più peer sono connessi, alcuni peer riceveranno una notifica l'altro no. A volte tutti vengono avvisati correttamente. Sono stato in grado di rintracciare la causa principale di esso. Succede anche quando un peer chiama il suo metodo di disconnessione. –

risposta

8

La mia unica soluzione a questo tipo di problema è stata quella di avere una relazione 1-1 tra sessioni e peer. Complifica l'invio di trasmissioni, ma almeno consente disconnessioni e pulizia a livello di pari tramite la disconnessione/rimozione della sessione stessa.

Aggiornamento

di approfondire la mia risposta originale, al fine di essere in grado di inviare dati a peer connessi è necessario mantenere un riferimento alla sessione che è stato creato per ogni peer. Sto usando un dizionario mutabile per questo.

Una volta che l'invito è stato inviato/accettato con una nuova sessione, utilizzare il metodo MCSession delegato per aggiornare il dizionario:

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

Tutti i peer possono essere raggiunti con un metodo che restituisce tutti i valori del dizionario, ed a sua volta tutta connectedPeers (in questo caso uno) per ogni MCSession:

- (NSArray *)allConnectedPeers { 

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

} 

invio di dati a un particolare pari o attraverso trasmissione può essere fatto con un metodo come questo:

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

Per quanto riguarda lo stesso framework, sono d'accordo con te @ArjunMehta. Non puoi fare affidamento su di esso per qualcosa di diverso dai semplici casi d'uso. Non ha funzionato affatto nel primo Xcode 5 beta e da allora Apple non ha fatto quasi nulla. – ChrisH

+1

Aggiungerei la mia voce a quella chiamata, è una tale promessa, ma abbiamo dovuto aspettare un periodo di tempo frustrante per farlo funzionare, e da allora non gli è stato dato molto amore. – Cocoadelica

+0

È un'idea così eccitante!Spero che abbia funzionato così facilmente come è stato concepito, ma sembra essere una cosa pignola. Ho notato che se disattivo il Bluetooth sui miei dispositivi è solo leggermente più affidabile. Ma sembra insinuarsi quando uno dei client chiude l'app (nemmeno una forza chiusa). –

2

Avete provato a disconnettere la sessione prima che l'applicazione si chiuda? Questo dovrebbe rimuovere correttamente il peer dalla sessione e ripulire tutte le risorse allocate per il peer.

In particolare voglio dire qualcosa di simile [self.peer disconnect] in applicationWillTerminate:

+0

Ho provato questo, sì. La mia applicazione idealmente supporta lo sfondo, quindi applicationWillTerminate non viene nemmeno chiamato. didEnterBackgroundDoes viene chiamato e sto cercando di fare qualcosa lì. Ma ancora, senza fortuna, anche se provo a disconnettere il peer dalla sessione. Penso che potresti voler dire [self.session disconnect]? –

+0

Ho scoperto che la maggior parte delle volte ottiene MCSessionStateNotConnected. Tuttavia, a volte alcuni peers non vengono avvisati. Ho visto questo anche quando viene disconnessa sul client. –

+0

Questo è un caso di test diverso. Ad esempio, l'app non funzionante dovrebbe funzionare (il che sarebbe simile allo spostamento fuori intervallo, ad esempio). – fishinear

0

non ho potuto ottenere la risposta accettata a mai lavorare, in modo da che cosa ho fatto, invece è di avere un timer che avrebbe sparato a reimpostare la connessione quando il browser potrebbe non segnare collegato e non c'erano altri colleghi connessi.

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

}

1

Ho avuto problemi simili. Sembra però che se ho eseguito la mia app su un dispositivo iOS e connesso a un altro, quindi esco e rilancio (diciamo quando eseguo nuovamente Xcode), quindi sono in una situazione in cui ottengo un messaggio Connected e quindi un Not Connected messaggio un po 'più tardi. Questo mi stava buttando via. Ma guardando più attentamente, posso vedere che il messaggio Non connesso è in realtà destinato a un peer-ID diverso da quello che è connesso.

Penso che il problema qui sia che la maggior parte dei campioni che ho visto si preoccupano solo del displayName del peerID e trascurano il fatto che è possibile ottenere più peerID per lo stesso dispositivo/displayName.

Ora sto verificando prima il displayName e poi verificando che il peerID sia lo stesso, facendo un confronto dei puntatori.

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

... 
+1

isEqual sull'oggetto peer potrebbe funzionare anche –

+0

displayName può essere identico per diversi peer, quindi non si dovrebbe fare nulla con displayName tranne che visualizzarlo. Il tuo dizionario _players dovrebbe essere digitato da peerID, non displayName. – fishinear

0

È possibile eliminare il peer dal MCBrowserViewController con seguente codice a Swift 3:

self.mySession.cancelConnectPeer(self.myPeerID) 
+0

Come fai a sapere quando farlo? – fishinear

Problemi correlati