40 votes

Pourquoi mon pair MCSession se déconnecte-t-il au hasard?

Im en utilisant MCNearbyServiceBrowser et MCNearbyServiceAdvertiser pour joindre deux pairs pour un MCSession. Je suis capable d'envoyer des données entre eux en utilisant MCSession de la méthode sendData. Tout semble fonctionner comme prévu jusqu'à ce que je aléatoirement (et non pas en raison de tout événement, je contrôle, de recevoir un MCSessionStateNotConnected via la session MCSessionDelegate didChangeState gestionnaire. En outre, la MCSession de connectedPeers tableau n'a plus de mes pairs.

Deux questions: Pourquoi? et Comment faire pour garder l'MCSession de la déconnexion?

26voto

Andrew Cone Points 701

C'est un bug que je viens de signaler à Apple. Les documents affirment que le rappel didReceiveCertificate est facultatif, mais ce n'est pas le cas. Ajoutez cette méthode à votre MCSessionDelegate :

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

Les déconnexions aléatoires devraient cesser.

17voto

PsychoDad Points 7582

Mise à JOUR Après l'aide d'un ticket de support pour Apple, ils ont confirmé que l'appel sendData trop souvent et avec trop de données peut provoquer des déconnexions.

J'ai eu des déconnexions lors de la frappe des points de rupture et lorsque la semi-finition. Depuis les points de rupture ne se fera pas sur l'app store, vous devez gérer la semi-finition du cas par le début d'une tâche en arrière-plan lorsque votre application est sur le point d'entrer dans le fond. Puis à la fin de cette tâche lorsque votre application est de retour au premier plan. Sur iOS 7 ce qui donne environ 3 minutes de fond qui est mieux que rien.

Une autre stratégie serait de planifier une notification locale pour peut-être 15 secondes avant que votre arrière-plan de l'expiration de la durée en utilisant [[UIApplication sharedApplication] backgroundTimeRemaining], de cette façon, vous pouvez apporter à l'utilisateur de retourner dans l'application avant de la suspend et le multi pairs cadre doit être à l'arrêt. Peut-être que la notification locale permettrait de les avertir que leur session va expirer dans les 10 secondes, ou quelque chose...

Si la tâche en arrière-plan expire et l'application est toujours en arrière-plan, vous avez à abattre tout ce qui concerne le multi-peer connectivité, sinon vous obtiendrez des plantages.

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

Vous voudrez aussi de ce gestionnaire dans votre MCSession délégué en raison de bug Apple:

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

11voto

SG1 Points 1061

Il existe de nombreuses causes de cette situation, et les deux réponses jusqu'à présent sont tous les deux corrects dans mon expérience. Un autre que vous trouverez dans d'autres questions similaires est: est-ce Seulement un pair peut accepter une autre invitation.

Donc, pour clarifier, si vous configurez une application lorsque tous les appareils sont à la fois les annonceurs et les navigateurs, tous les appareils peuvent librement inviter d'autres ont trouvé à se joindre à une session. Cependant, entre deux appareils, un seul appareil peut accepter l'invitation et de se connecter à l'autre appareil. Si les deux appareils s'accepter les uns les autres invitations qu'ils se déconnectent en une minute ou moins.

Notez que cette limitation n'empêche pas le comportement désiré parce que - contrairement à ce que mon intuition l'a dit avant, j'ai construit mon multipeer mise en œuvre - lorsqu'un appareil accepte l'invitation et se connecte à un autre appareil à la fois reliés et de recevoir de connexion délégué méthodes, et peut envoyer des messages les uns aux autres.

Par conséquent, si vous connectez des périphériques qui les parcourir et de faire de la publicité, envoyer des invitations librement, mais d'accepter que seulement un d'une paire.

Le problème d'accepter uniquement l'une des deux invitations peuvent être résolus d'une multitude de façons. Pour commencer, comprendre que vous pouvez passer n'importe quel objet ou un dictionnaire (archivé en tant que données) que l' context argument dans une invitation. Par conséquent, les deux appareils ont accès à tout arbitraire d'informations sur les autres (et bien sûr lui-même). Donc, vous pourriez utiliser au moins une de ces stratégies:

  • simplement, compare: le nom d'affichage de peerID. Mais rien ne garantit qu'elles ne seront pas égaux.
  • stocker la date de votre multipeer contrôleur a été initialisé et l'utiliser pour la comparaison
  • donner à chaque peer un UUID et l'envoyer à des fins de comparaison (ma technique, dans lequel chaque dispositif - en effet, chaque utilisateur de l'application sur un périphérique a une persistance de la UUID il emploie).
  • etc - tout objet qui prend en charge les deux NSCoding et compare: fera l'affaire.

1voto

DannyJi Points 11

Je me déconnectais immédiatement après avoir accepté la demande de connexion. Observant cet état, je l'ai vu passer de MCSessionStateConnected à MCSessionStateNotConnected.

Je crée mes sessions avec:

 [[MCSession alloc] initWithPeer:peerID]
 

PAS la méthode d'instanciation traitant des certificats de sécurité:

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

D'après le conseil d'Andrew ci-dessus, j'ai ajouté la méthode des délégués.

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

et les déconnexions arrêtés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X