为什么我的MCSession对等端会随机断开连接?

til*_*arr 40 objective-c ios7 multipeer-connectivity

我使用MCNearbyServiceBrowser和MCNearbyServiceAdvertiser将两个对等体连接到MCSession.我可以使用MCSession的sendData方法在它们之间发送数据.所有似乎都按预期工作,直到我随机(并且不是由于我控制的任何事件)通过会话的MCSessionDelegate didChangeState处理程序接收MCSessionStateNotConnected.此外,MCSession的connectedPeers数组不再拥有我的同行.

两个问题:为什么?以及如何防止MCSession断开连接?

And*_*one 26

这是一个错误,我刚刚向Apple报告.文档声称didReceiveCertificate回调是可选的,但事实并非如此.将此方法添加到您的MCSessionDelegate:

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

随机断开连接应该停止.

  • 即使在实施之后仍然会断开连接 (7认同)

jjx*_*tra 17

更新使用Apple支持票后,他们确认过于频繁地调用sendData并且数据太多会导致断开连接.

在击中断点和背景时,我已经断开连接.由于断点不会发生在应用商店中,因此您需要在应用即将进入后台时开始后台任务来处理后台处理案例.然后当您的应用程序返回到前台时结束此任务.在iOS 7上,这给你大约3个背景分钟,这比没有好.

另一种策略是在您的后台时间到期之前安排本地通知可能15秒[[UIApplication sharedApplication] backgroundTimeRemaining],这样您就可以在用户暂停之前将用户带回应用程序,并且必须关闭多对等框架.也许本地通知会警告他们他们的会话将在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
}
Run Code Online (Sandbox Code Playgroud)

由于Apple bug,您还需要在MCSession委托中使用此处理程序:

- (void) session:(MCSession*)session didReceiveCertificate:(NSArray*)certificate fromPeer:(MCPeerID*)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler
 {
     if (certificateHandler != nil) { certificateHandler(YES); }
 }
Run Code Online (Sandbox Code Playgroud)


SG1*_*SG1 11

造成这种情况的原因很多,到目前为止,这两个答案在我的经历中都是正确的.您在其他类似问题中可以找到的另一个问题是:只有一个同伴可以接受另一个人的邀请.

因此,澄清一下,如果您设置的应用程序所有设备都是广告商和浏览器,任何设备都可以自由邀请任何其他设备加入会话.但是,在任何两个给定设备之间,只有一个设备可以实际接受邀请并连接到另一个设备.如果两个设备都接受彼此的邀请,他们将在一分钟或更短的时间内断开连接.

请注意,此限制并不会阻止所需的行为,因为 - 与我在构建多重同步实现之前所说的直觉不同 - 当一个设备接受邀请并连接到另一个设备时,它们都会连接并接收连接委托方法并可以相互发送消息.

因此,如果您要连接既浏览又要做广告的设备,请自由发送邀请,但只接受其中一对.

只接受两个邀请之一的问题可以通过多种方式解决.首先,要了解您可以将任意对象或字典(存档为数据)作为context邀请中的参数传递.因此,两个设备都可以访问关于另一个(当然还有其自身)的任意信息.所以,你至少可以使用这些策略:

  • 只是compare:peerID的显示名称.但是不能保证这些不平等.
  • 存储多重控制器初始化的日期并将其用于比较
  • 给每个对等体一个UUID并发送它进行比较(我的技术,其中每个设备 - 实际上是设备上app的每个用户 - 都有它使用的持久UUID).
  • 等 - 任何支持NSCoding的对象都可以compare:.