2013-09-21 51 views
38

進出口使用MCNearbyServiceBrowser和MCNearbyServiceAdvertiser連接兩個同伴到MCSession。我可以使用MCSession的sendData方法在它們之間發送數據。所有似乎按預期工作,直到我隨機(而不是由於我控制的任何事件)通過會話的MCSessionDelegate didChangeState處理程序接收MCSessionStateNotConnected。另外,MCSession的connectedPeers數組不再擁有我的對等體。爲什麼我的MCSession對等體會隨機斷開連接?

兩個問題:爲什麼?和我如何保持MCSession斷開連接?

+0

我有同樣的問題,但我有一些數據發送後斷開連接。你有解決這個問題嗎? – Moonkid

+0

我注意到的一件事是在調試器中暫停MCSession。我最終編寫了一個機制來重新建立會話,如果它被丟棄。 – tillerstarr

+0

我有同樣的問題。我注意到,如果一個設備是背景燈,並且消息被髮送給它,則會發生斷開連接。 – jjxtra

回答

17

UPDATE在使用Apple支持憑單後,他們確認經常調用sendData並且數據太多會導致斷開連接。

擊球破發點並backgrounding時,當我有斷開。由於應用商店不會發生斷點,因此您需要在應用即將進入後臺時開始後臺任務來處理後臺情況。然後在您的應用回到前臺時結束此任務。在iOS 7上,這給了你大約3分鐘的背景,比沒有好。

另一個策略是在背景時間到期前使用[[UIApplication sharedApplication] backgroundTimeRemaining]安排本地通知大概15秒鐘,這樣您可以在掛起應用程序之前將用戶帶回應用程序,並且必須關閉多對等框架。也許本地通知會警告他們,他們的會話將在10秒內過期...

如果後臺任務到期並且應用程序仍在後臺,則必須拆除與多點對等連接相關的所有內容,否則你會碰到崩潰。

- (void) createExpireNotification 
{ 
    [self killExpireNotification]; 

    if (self.connectedPeerCount != 0) // if peers connected, setup kill switch 
    { 
     NSTimeInterval gracePeriod = 20.0f; 

     // create notification that will get the user back into the app when the background process time is about to expire 
     NSTimeInterval msgTime = UIApplication.sharedApplication.backgroundTimeRemaining - gracePeriod; 
     UILocalNotification* n = [[UILocalNotification alloc] init]; 
     self.expireNotification = n; 
     self.expireNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:msgTime]; 
     self.expireNotification.alertBody = TR(@"Text_MultiPeerIsAboutToExpire"); 
     self.expireNotification.soundName = UILocalNotificationDefaultSoundName; 
     self.expireNotification.applicationIconBadgeNumber = 1; 

     [UIApplication.sharedApplication scheduleLocalNotification:self.expireNotification]; 
    } 
} 

- (void) killExpireNotification 
{ 
    if (self.expireNotification != nil) 
    { 
     [UIApplication.sharedApplication cancelLocalNotification:self.expireNotification]; 
     self.expireNotification = nil; 
    } 
} 

- (void) applicationWillEnterBackground 
{ 
    self.taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^ 
    { 
     [self shutdownMultiPeerStuff]; 
     [[UIApplication sharedApplication] endBackgroundTask:self.taskId]; 
     self.taskId = UIBackgroundTaskInvalid; 
    }]; 
    [self createExpireNotification]; 
} 

- (void) applicationWillEnterForeground 
{ 
    [self killExpireNotification]; 
    if (self.taskId != UIBackgroundTaskInvalid) 
    { 
     [[UIApplication sharedApplication] endBackgroundTask:self.taskId]; 
     self.taskId = UIBackgroundTaskInvalid; 
    } 
} 

- (void) applicationWillTerminate 
{ 
    [self killExpireNotification]; 
    [self stop]; // shutdown multi-peer 
} 

您也想這個處理程序在你的MCSession代表由於蘋果的bug:

- (void) session:(MCSession*)session didReceiveCertificate:(NSArray*)certificate fromPeer:(MCPeerID*)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler 
{ 
    if (certificateHandler != nil) { certificateHandler(YES); } 
} 
+0

背景時,您可以在將應用程序從後臺恢復時保持連接嗎? – Tim

+0

只要您的背景時間沒有用完,您就可以使用。如果是這樣,你別無選擇,只能殺死會議或崩潰。 – jjxtra

+0

@PsychoDad在你遇到蘋果DTS的時候,你是否經常在被認爲調用sendData的東西上學到任何東西? –

25

這是一個錯誤,這是我剛剛報道了蘋果。該文檔聲稱didReceiveCertificate回調是可選的,但事實並非如此。這種方法添加到您的MCSessionDelegate

- (void) session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler 
{ 
    certificateHandler(YES); 
} 

隨機斷開應該停止。

+7

即使在執行此操作後仍會斷開連接 – jjxtra

+1

對於我來說,也不會爲它修復(在swift中) – berliner

+1

如果您已收到帶有MCSessionStateConnected值的didChangeState消息並且可以成功發送數據,那麼您已經完成一個連接,這不是你的問題。其他答案之一可能有更多的信息。然而,如果你(像我一樣)對你爲什麼試圖接受連接感到困惑,你會看到MCSessionStateConnecting,然後在幾秒鐘後看到MCSessionStateNotConnected而沒有其他解釋,那麼這裏給出的答案很可能就是你的問題。 – GrandOpener

11

這方面有很多的原因,這兩個答案迄今都是以我的經驗都正確。另外,你會在其他類似的問題,發現是這樣的:只有一個節點可以接受別人的邀請

所以,澄清,如果你設置了一個應用程序,所有設備均是廣告商和瀏覽器,任何設備可以隨意邀請任何人發現加入會話。但是,在任何兩個給定設備之間,只有一個設備可以實際接受邀請並連接到其他設備。如果兩臺設備接受彼此的邀請,他們將在一分鐘或更短時間內斷開連接。

請注意,此限制並不妨礙所需的行爲,因爲 - 不像我的直覺所述,在構建我的多路複用器實現之前 - 當一個設備接受邀請並連接到另一設備時,它們都會連接並接收連接委託方法並可以發送對方的消息。

因此,如果您連接的設備既瀏覽和廣告,自由發送邀請,但只接受一對其中之一。

只接受兩個邀請之一的問題可以通過無數種方式解決。首先,要明白,您可以在邀請中傳遞任意任意對象或字典(存檔爲數據)作爲context參數。因此,這兩個設備都可以訪問任何關於其他設備的信息(當然也可以)。因此,您至少可以使用以下策略:

  • 只是compare: peerID的顯示名稱。但是不能保證這些不會是平等的。
  • 存儲區multipeer控制器被初始化,並利用它來進行比較
  • 給每個同行一個UUID,並將其發送比較(我的技術,其中每個設備的日期 - 設備上的應用程序確實每個用戶 - 擁有它使用的持續UUID)。
  • 等 - 任何支持NSCoding和compare:的對象都可以。
+0

我認爲這是我的問題。所以我甚至編造了一個令人費解的延遲邀請,但是他們都還沒有連接。 – daidai

+1

這實際上是這個問題:'請注意:模擬器不支持藍牙網絡.' – daidai

1

我在接受連接請求後立即斷開連接。觀察狀態,我看到它從MCSessionStateConnected更改爲MCSessionStateNotConnected。

我創造我的會議有:

[[MCSession alloc] initWithPeer:peerID] 

不實例化方法處理安全證書:

- (instancetype)initWithPeer:(MCPeerID *)myPeerID securityIdentity:(NSArray *)identity encryptionPreference:(MCEncryptionPreference)encryptionPreference 

基於安德魯的頂端的上方,我添加了委託方法

- (void) session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler { 
     certificateHandler(YES); 
    } 

並斷開連接。

3

我一直有類似的問題。但似乎如果我已經在一臺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; 

... 
+0

這仍然是相關的,在Swift3上2年! – timothykc

相關問題