2014-04-11 75 views
13

考慮到社區遇到的所有錯誤,我想知道這個Multipeer連接框架是否可以在現實世界中使用。我想我正確地設置它,但我嘗試過的所有其他示例項目都遇到類似的問題。Multipeer連接框架 - 丟失的對端留在會話中

我有可能被捆綁到一些固有的卓悅什麼問題的問題,我不出來,但基本問題如下:

  • 我有一個活動MCSession與一些同行。
  • 現在,如果設備在會話中,然後強制退出,則「對等」會保持連接狀態的時間不確定。
  • 即使對該對等方調用browser:lostPeer:方法並且不再在瀏覽器中顯示爲 「Nearby」,我也無法強制該用戶出來。
  • session:peer:didChangeState:方法不被該對等方調用。
  • 當強制退出的同伴回到應用程序時,它們被browser:foundPeer:withDiscoveryInfo:再次「發現」,但仍存在於session.connectedPeers NSArray中。很明顯,他們沒有收到關於會話的任何數據或更新,但實際上並沒有連接。
  • 似乎工作原理的唯一似乎將MCSessionStateNotConnected註冊到會話的方法是將該對等體重新連接到原始會話。然後重複調用session:peer:didChangeState:,其中peerID的新實例爲MCSessionStateConnected,並且在peerID的舊實例與MCSessionStateNotConnected調用後不久。

樣品聊天應用程序演示了這個問題很好:https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html

因爲似乎沒有被任何手動強制從會話中刪除對,我應該怎麼辦?我應該嘗試重建會議嗎?

這個框架看起來有點亂,但我試圖保留判斷!

+0

我有一個工作的應用程序,但把它擴大近8名同行,現在它破產需要:(我有。發現一個問題到目前爲止,在進入後臺時不會無意中強烈地引用MC對象(我知道,適用範圍比MC更廣泛,但提醒有幫助!) – 300baud

+0

我有同樣的問題有時MCSession的會話:peer :didChangeState:不會使用MCSessionStateNotConnected爲具有斷開連接的對等方調用。當連接多個對等點時,某些對等點將收到通知其他不會。有時候每個人都會得到正確的通知我已經能夠找出它的根本原因。即使對方正在調用其斷開方法,也會發生這種情況。 –

回答

8

我對這類問題的唯一解決方法是在會話和對等點之間建立一個1-1關係。它使發送廣播變得複雜,但至少允許通過斷開/移除會話本身來進行同級斷開和清理。

更新

要闡述我原來的答覆,爲了能夠將數據發送到與同齡人有必要維持到爲每個對等創建的會話的引用。我一直在使用可變字典。

一旦邀請已發/有一個新的會話接受,使用MCSession委託方法來更新詞典:

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

所有的同齡人可以返回字典的所有值的方法來訪問,並且反過來所有connectedPeers(在這種情況下,一個),用於每個MCSession

- (NSArray *)allConnectedPeers { 

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

} 

將數據發送到特定的對等體或經由廣播可以用這樣的方法完成的:

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

至於框架本身,我同意你@ArjunMehta。除了簡單的用例之外,你不能依賴它。它在第一個Xcode 5測試版中完全不起作用,而蘋果自此以後幾乎沒有做任何事情。 – ChrisH

+1

我會加我的聲音給那個電話,它有這樣的承諾,但我們不得不等待一段令人沮喪的時間才能工作,然後從那以後它就沒有被給予過多的愛。 – Cocoadelica

+0

這是一個非常激動人心的想法!我希望它的工作很容易,但它似乎是一個挑剔的事情。我注意到,如果我在我的設備上禁用藍牙,它只會稍微可靠一些。但是,當一個客戶關閉應用程序時(似乎並沒有強制退出),它似乎就會出錯。 –

2

您是否在應用程序關閉之前嘗試斷開會話?這應該正確地從會話中刪除對等體並清除爲對等體分配的任何資源。

具體來說,我的意思是在applicationWillTerminate:

+0

我試過這個,是的。我的應用程序將理想地支持後臺,所以applicationWillTerminate甚至不會被調用。 didEnterBackground被調用,我試圖在那裏做一些事情。但是,即使我嘗試斷開會話連接,也沒有運氣。我想你可能意思是[self.session斷開]? –

+0

我發現它大部分時間都會得到MCSessionStateNotConnected。但是,有時候一些同行沒有得到通知。即使在客戶端調用斷開連接時,我也看到了這一點。 –

+0

這是一個不同的測試案例。硬性應用程序也應該可以工作(例如,這類似於移出範圍)。 – fishinear

0

[self.peer disconnect]我無法接受的答案永遠工作,所以我做了什麼,而不是是有一個計時器,將觸發重置連接時,瀏覽器將不報告並沒有其他連接的同伴。

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

我一直有類似的問題。似乎如果我已經在一臺iOS設備上運行我的應用程序並連接到另一臺設備,然後退出並重新啓動(例如,當我從Xcode重新運行時),那麼我處於一種情況,在該情況下,我會收到已連接消息,然後是未連接稍後留言。這讓我失望了。但仔細觀察,我可以看到「未連接」消息實際上是指與已連接的不同peerId。

我認爲這裏的問題是我見過的大多數示例只關心peerID的displayName,而忽略了可以爲同一設備/ displayName獲取多個peerID的事實。

我現在先檢查displayName,然後通過比較指針來驗證peerID是否相同。

- (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也可以工作 –

+0

displayName對於不同的對等體可以是相同的,因此除了顯示它之外,您不應該對displayName進行任何操作。您的_players字典應由peerID鍵入,而不是displayName。 – fishinear

0

您可以刪除MCBrowserViewController同行與斯威夫特3下面的代碼:

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

你怎麼知道什麼時候這樣做? – fishinear