2014-04-11 5 views
13

Ich frage mich, ob dieses Multipeer Connectivity-Framework für die Verwendung in der realen Welt bereit ist, angesichts all der Fehler, die von der Gemeinschaft aufgetreten sind. Ich denke, ich richte es richtig ein, aber all die anderen Beispielprojekte, die ich ausprobiert habe, stoßen auf ähnliche Probleme.Multipeer Connectivity Framework - Lost Peer bleibt in Sitzung

Das Problem, das ich habe zu einem gewissen Thema gebunden werden kann, inhärent Bonjour oder etwas, ich kann es nicht herausgefunden, aber im Grunde ist das Problem wie folgt:

  • ich eine aktives MCSession habe mit eine Anzahl von Peers.
  • Nun, wenn ein Gerät in einer Sitzung ist, und dann Force beendet, bleibt dieser "Peer" für eine unbestimmte Zeit verbunden.
  • Es gibt nichts, was ich tun kann, um diesen Benutzer zu zwingen, obwohl die browser:lostPeer: Methode für diesen Peer aufgerufen wird und nicht mehr im Browser als "Nearby" angezeigt wird.
  • Die Methode session:peer:didChangeState: wird für diesen Peer nicht aufgerufen.
  • Wenn der Peer, der die Kraft verlassen hat, zurück zur App kommt, werden sie wieder von der browser:foundPeer:withDiscoveryInfo: "gefunden", existieren aber auch noch in der session.connectedPeers NSArray. Offensichtlich erhalten sie keine Daten oder Updates über die Sitzung und sind nicht wirklich verbunden.
  • Die einzige Sache, die funktioniert, um diesen ursprünglichen Peer als MCSessionStateNotConnected zu der Sitzung zu registrieren, ist, indem Sie diesen Peer wieder mit der ursprünglichen Sitzung verbinden. Dann gibt es einen doppelten Anruf an session:peer:didChangeState:, wo die neue Instanz der PeerID MCSessionStateConnected ist und kurz nach der alten Instanz der PeerID mit MCSessionStateNotConnected aufruft.

Die Probe Chat-Anwendung demonstriert dieses Problem gut: https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html

Da es keine Möglichkeit zu sein scheint manuell einen Peer aus der Sitzung entfernen zwingen, was soll ich tun? Soll ich die Session irgendwie neu aufbauen?

Dieses Framework scheint ein bisschen Chaos, aber ich versuche, das Urteil zu reservieren!

+0

Ich hatte eine funktionierende Anwendung aber brauchte es letzten 8 Kollegen zu erweitern, seine jetzt pleite :(ich habe. ein Problem bisher gefunden, nicht versehentlich starke Referenzen auf MC-Objekte, wenn in den Hintergrund (ich weiß, gilt breiter als nur MC .. aber eine Erinnerung hilft!) – 300baud

+0

Ich habe das gleiche Problem Manchmal MCSession Sitzung: Peer : didChangeState: wird nicht mit MCSessionStateNotConnected für einen Peer aufgerufen, der die Verbindung getrennt hat Wenn mehrere Peers verbunden sind, werden einige Peers benachrichtigt andere werden nicht. Manchmal werden alle richtig benachrichtigt. Ich war in der Lage, die Ursache dafür aufzuspüren. Es passiert sogar, wenn ein Peer seine Trennmethode aufruft. –

Antwort

8

Meine einzige Problemumgehung für diese Art von Problem war, eine 1-1 Beziehung zwischen Sitzungen und Peers zu haben. Es erschwert das Senden von Broadcasts, ermöglicht jedoch zumindest das Trennen und Bereinigen auf Peer-Ebene durch Trennen/Entfernen der Sitzung selbst.

aktualisieren

auf meiner ursprünglichen Antwort zu erarbeiten, um in der Lage zu sein, Daten an die angeschlossenen Peers zu senden ist es notwendig, einen Verweis auf die Sitzung zu halten, die für jeden Peer erstellt wurde. Ich habe dafür ein veränderbares Wörterbuch benutzt.

Sobald die Einladung mit einer neuen Sitzung gesendet/akzeptiert wurde, verwenden Sie die MCSession Delegatmethode das Wörterbuch zu aktualisieren:

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

Alle Peers können mit einem Verfahren zugegriffen werden, die alle Werte des Wörterbuchs zurückgibt, und der Reihe nach alle connectedPeers (in diesem Fall ein) für jede MCSession:

- (NSArray *)allConnectedPeers { 

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

} 

Senden von Daten an einen bestimmten Peer oder per Broadcast kann mit einer Methode wie folgt durchgeführt werden:

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

Was das Framework selbst angeht, stimme ich dir @ArjunMehta zu. Sie können sich auf nichts anderes als auf einfache Anwendungsfälle verlassen. Es funktionierte überhaupt nicht in der ersten Xcode 5-Beta, und Apple hat seitdem fast nichts mehr damit gemacht. – ChrisH

+1

Ich würde meine Stimme zu diesem Ruf hinzufügen, es ist so vielversprechend, aber wir mussten frustrierend lange warten, bis es überhaupt funktionierte, und seitdem ist ihm nicht viel Liebe gegeben worden. – Cocoadelica

+0

Es ist so eine aufregende Idee!Ich wünschte, es würde so einfach funktionieren wie es gemacht wird, aber es scheint ein heikles Ding zu sein. Ich habe bemerkt, dass wenn ich Bluetooth auf meinen Geräten deaktiviere, es nur etwas zuverlässiger ist. Aber es scheint einen Bug zu bekommen, wenn einer der Clients die App schließt (nicht einmal eine Kraft, die gekündigt wird). –

2

Haben Sie versucht, die Sitzung zu trennen, bevor die Anwendung geschlossen wird? Dies sollte den Peer aus der Sitzung entfernen und alle für den Peer zugewiesenen Ressourcen bereinigen.

Konkret meine ich so etwas wie [self.peer disconnect] in applicationWillTerminate:

+0

Ich habe das versucht, ja. Meine Anwendung würde im Idealfall Hintergrund unterstützen, so dass applicationWillTerminate nicht einmal aufgerufen wird. didEnterBackgroundWird angerufen und ich versuche dort etwas zu tun. Aber immer noch kein Glück, auch wenn ich versuche, den Peer von der Sitzung zu trennen. Ich glaube du meinst [self.session disconnect]? –

+0

Ich habe gefunden, dass es die meiste Zeit die MCSessionStateNotConnected erhält. Manchmal werden einige Peers jedoch nicht benachrichtigt. Ich habe das selbst gesehen, wenn die Verbindung zum Client unterbrochen wird. –

+0

Das ist ein anderer Testfall. Hard-Quitting der App sollte auch funktionieren (das wäre ähnlich wie außerhalb der Reichweite, zum Beispiel). – fishinear

0

ich nicht die akzeptierte Antwort bekommen konnte, jemals arbeiten, also was ich getan habe ist, anstatt einen Timer, die die Verbindung zurückgesetzt, wenn der Browser nicht würde berichten feuern würde verbunden und es gab keine anderen verbundenen Peers.

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

Ich habe ähnliche Probleme gehabt. Es scheint jedoch, dass, wenn ich meine App auf einem iOS-Gerät ausgeführt und verbunden, dann beenden und neu starten (sagen wir, wenn ich von Xcode erneut ausführen), dann bin ich in einer Situation, in der ich eine Connected-Nachricht und dann eine nicht verbundene Nachricht etwas später. Das hat mich abgeworfen. Aber wenn ich genauer hinschaue, kann ich sehen, dass die Nachricht "Nicht verbunden" eigentlich für eine andere Peer-ID gedacht ist als die, die verbunden ist.

Ich denke, das Problem hier ist, dass die meisten Beispiele, die ich gesehen habe, nur interessieren, die der PeerID, und vernachlässigen Sie die Tatsache, dass Sie mehrere PeerIDs für das gleiche Gerät/displayName erhalten können.

Ich überprüfe nun zuerst den displayName und überprüfe dann, dass die PeerID die gleiche ist, indem ich einen Vergleich der Zeiger mache.

- (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 auf dem Peer-Objekt würde auch funktionieren –

+0

displayName kann für verschiedene Peers identisch sein, also sollten Sie mit dem displayName nichts anderes tun, als es anzuzeigen. Ihr _players-Wörterbuch sollte von peerID, nicht von displayName codiert sein. – fishinear

0

Sie können die Peer aus dem MCBrowserViewController löschen mit folgenden Code in Swift 3:

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

Woher wissen Sie, wann dies zu tun ist? – fishinear