我想知道这个Multipeer Connectivity框架是否可以在现实世界中使用,考虑到社区遇到的所有错误。我认为我的设置正确,但我尝试过的所有其他示例项目都遇到了类似的问题。
我遇到的问题可能与Bonjour固有的某些问题有关,我无法弄清楚,但基本上问题如下:
MCSession
和许多同行。browser:lostPeer:
方法并且不再在浏览器中显示为该用户,我也无法强制该用户离开
"邻近" 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)
我对此类问题的唯一解决方法是在会话和同行之间建立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
(在本例中为1):
- (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;
}
}
答案 1 :(得分:2)
您是否尝试在应用程序关闭前断开会话?这应该正确地从会话中删除对等体并清除为对等体分配的任何资源。
具体来说,我的意思是[self.peer disconnect]
applicationWillTerminate:
答案 2 :(得分:1)
我一直有类似的问题。看来,如果我在一台iOS设备上运行我的应用程序,并连接到另一台设备,然后退出并重新启动(比如当我从Xcode重新运行时),那么我处于一种情况下,我收到一条已连接的消息,然后是一台未连接的消息稍后。这让我失望了。但仔细观察,我可以看到Not Connected消息实际上是针对与已连接的消息不同的peerId。
我认为这里的问题是我见过的大多数样本只关心peerID的displayName,而忽略了你可以为同一个device / 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;
...
答案 3 :(得分:0)
我无法获得可接受的答案,所以我所做的就是有一个计时器,当浏览器报告未连接且没有其他连接的对等体时,将触发重置连接。
-(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];
}
);
}
}
...
}
答案 4 :(得分:0)
您可以使用Swift 3中的以下代码从MCBrowserViewController中删除对等端:
self.mySession.cancelConnectPeer(self.myPeerID)