简体   繁体   中英

Multipeer Connectivity kill session

I'm using a host/client approach to using MultiPeer Connectivity.

So, when a user his the disconnect button

-(IBAction)disconnect:(id)sender {

    [_appDelegate.mcManager.session disconnect];

    [_arrConnectedDevices removeAllObjects];



    ConnectionsViewController *game = [self.storyboard instantiateViewControllerWithIdentifier:@"ConnectionsViewController"];

    [self presentViewController:game animated:YES completion:nil];

}

Now, this works fine. From the hosts point of view it receives a disconnect message in the log. and the client moves to the new view controller. And the table is updated. with this.

-(void)peerDidChangeStateWithNotification:(NSNotification *)notification{
    MCPeerID *peerID = [[notification userInfo] objectForKey:@"peerID"];
    NSString *peerDisplayName = peerID.displayName;
    MCSessionState state = [[[notification userInfo] objectForKey:@"state"] intValue];

    if (state != MCSessionStateConnecting) {
        if (state == MCSessionStateConnected) {
            if (_makeSureImHost) {
                [_arrConnectedDevices addObject:peerDisplayName];

                [_tblConnectedDevices performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
            }

            else {
                [self sendMessageToHostWithMessage:@"deviceInfo"];
            }
        }
        else if (state == MCSessionStateNotConnected){
            if ([_arrConnectedDevices count] > 0) {
                int indexOfPeer = (int)[_arrConnectedDevices indexOfObject:peerDisplayName];
                [_arrConnectedDevices removeObjectAtIndex:indexOfPeer];

                NSLog(@"%@ Disconnected", peerDisplayName);

                [_tblConnectedDevices performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

                _tblConnectedDevices.frame = CGRectMake(_backgroundImage.frame.size.width / 2 - 150, self.backgroundImage.frame.size.height / 3, 300,  150);


            }
        }
    }
}

END OF LOBBY VIEW CONTROLLER

START OF CONNECTION VIEW CONTROLLER

When a client presses to browse for local devices this runs

- (IBAction)browseForDevices:(id)sender {
    [UIView animateWithDuration:0.5f
                     animations:^{
                         _searchButton.frame = CGRectMake(-100, self.backgroundImage.frame.size.height/2 + 60, 100, 35.0);
                         _hostButton.alpha = 0;
                         _modeLabel.alpha = 0;
                     }];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [[_appDelegate mcManager] setupPeerAndSessionWithDisplayName:[UIDevice currentDevice].name];
        [[_appDelegate mcManager] advertiseSelf:false];

        [[_appDelegate mcManager] setupMCBrowser];
        [[[_appDelegate mcManager] browser] setDelegate:self];
        _appDelegate.mcManager.browser.maximumNumberOfPeers = 1;

        _appDelegate.mcManager.browser.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
        [self presentViewController:[[_appDelegate mcManager] browser] animated:YES completion:nil];
    });

}

When a connection is established

-(void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController {
    [_appDelegate.mcManager.browser dismissViewControllerAnimated:NO completion:^{
        [self launchViewController];
    }];
}

-(void)launchViewController {
    LobbyViewController *lobby = [self.storyboard instantiateViewControllerWithIdentifier:@"LobbyViewController"];
    [self presentViewController:lobby animated:NO completion:nil];
}

From this

-(void)peerDidChangeStateWithNotification:(NSNotification *)notification {
    MCPeerID *peerID = [[notification userInfo] objectForKey:@"peerID"];
    NSString *peerDisplayName = peerID.displayName;
    MCSessionState state = [[[notification userInfo] objectForKey:@"state"] intValue];

    if (state != MCSessionStateConnecting) {
        if (state == MCSessionStateConnected) {
            [self browserViewControllerDidFinish:[[_appDelegate mcManager] browser]];

        }
    }
    else if (state == MCSessionStateNotConnected){
        if ([_arrConnectedDevices count] > 0) {
            int indexOfPeer = (int)[_arrConnectedDevices indexOfObject:peerDisplayName];
            [_arrConnectedDevices removeObjectAtIndex:indexOfPeer];


        }
    }
}

Now. When a connection is made for the first time. This all works flawlessly. It connects, loads the view, host starts the game, game works fine and data is transferred perfectly.

However, if you disconnect from the lobby. Get moved to the connection viewcontroller then browse for devices again. It will connect, however the lobby viewcontroller will NOT be in the view hierarchy and will close the browser and stay in the connection view controller.

Then, to top it off, the connection has been made. yet, when it receives a message from the host, it will send the response, twice.. or three times, or four, leading me to a dead end. The only thing I can presume is that the previous session is being remembered somehow from the "clients" point of view.

Now, steps I can take to avoid this mess. If I kill the app and relaunch it I can now connect again from the clients point of view. Which leads me to believe, the problem is on the clients end.

My problem is that I have to absolutely sort this out. So a disconnect will fully remove everything from the session. So they can reconnect again. And cannot rely on a message to tell the user to restart their application. It just cannot be.

Here's my entire MCManager.m file.

@implementation MCManager

-(id)init{
    self = [super init];

    if (self) {
        _peerID = nil;
        _session = nil;
        _browser = nil;
        _advertiser = nil;
    }

    return self;
}

-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName{
    _peerID = [[MCPeerID alloc] initWithDisplayName:displayName];

    _session = [[MCSession alloc] initWithPeer:_peerID];
    _session.delegate = self;
}

-(void)setupMCBrowser{
    _browser = [[MCBrowserViewController alloc] initWithServiceType:@"chat-files" session:_session];
}

-(void)advertiseSelf:(BOOL)shouldAdvertise{
    if (shouldAdvertise) {
        _advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:@"chat-files"
                                                           discoveryInfo:nil
                                                                 session:_session];
        [_advertiser start];
    }
    else{
        [_advertiser stop];
        _advertiser = nil;
    }
}

-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
    NSDictionary *dict = @{@"peerID": peerID,
                           @"state" : [NSNumber numberWithInt:state]
                           };

    [[NSNotificationCenter defaultCenter] postNotificationName:@"MCDidChangeStateNotification"
                                                        object:nil
                                                      userInfo:dict];
}


-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
    NSDictionary *dict = @{@"data": data,
                           @"peerID": peerID
                           };

    [[NSNotificationCenter defaultCenter] postNotificationName:@"MCDidReceiveDataNotification"
                                                        object:nil
                                                      userInfo:dict];
}


-(void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress{

}


-(void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error{

}


-(void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID{

}

@end

#import <MultipeerConnectivity/MultipeerConnectivity.h>

@interface MCManager : NSObject <MCSessionDelegate>

@property (nonatomic, strong) MCPeerID *peerID;
@property (nonatomic, strong) MCSession *session;
@property (nonatomic, strong) MCBrowserViewController *browser;
@property (nonatomic, strong) MCAdvertiserAssistant *advertiser;

-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName;
-(void)setupMCBrowser;
-(void)advertiseSelf:(BOOL)shouldAdvertise;
@end

If anyone knows what I'm doing wrong I'd much appreciate it. This is driving me nuts.

[[NSNotificationCenter defaultCenter] removeObserver:name:object:];

Has fixed all my problems. Hopefully helps some other people too.

With Swift, I end the multipeer session as follows (after completing checking the deinit of session tracker):

func stopSession() {
        self.serviceBrowser.stopBrowsingForPeers()
        self.serviceBrowser.delegate = nil
        
        self.serviceAdvertiser.stopAdvertisingPeer()
        self.serviceAdvertiser.delegate = nil

        self.session.disconnect()
        self.peerSessionIDs.removeAll()
        self.session.delegate = nil
        self.session = nil

        self.multipeerConnectivityService = nil
        self.serviceType = nil
    }

In other words, everything that was registered and the initializer is de-initialized. I am doing this in reverse order, but I'm not sure if order is important here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM