2

This is my first time posting on stackoverflow, and I'm aware of the strict posting requirements. Please let me know if I'm not following any of the guidelines.

I'm currently writing an IOS (8.4) application in Xcode, using Objective-C. The goal is to use MCSessions in order to stream data between IOS devices. I'm currently struggling with the concept of sessions, despite reading numerous posts here and elsewhere that attempt to clarify the topic. Here are the resources I'm already aware of:

https://developer.apple.com/videos/play/wwdc2013-708/

https://medium.com/@phoenixy/using-multipeer-connectivity-120abacb9db

Here's my current understanding: At the most basic level, you have an advertiser, and a browser. The advertiser has a local session, which allows them to "advertise". When the browser sees an advertiser, the browser sends an invite to the advertiser to his (the browser's) local MCSession. Assuming this is all correct, here's where I'm getting confused. The advertiser can accept the invite, and in the process, passes his local session to the invitationHandler.

I have implemented the following logic in code, as shown below. However, in tracing MCSession state changes for both the advertiser and browser, a connection is attempted, but the final state is always didNotNonnect.

Code for sending invitation (Browser):

[self.broadcasterBrowser invitePeer:[broadcasterPeerIDs objectAtIndex:indexPath.row]
        toSession: self.appDelegate.mpcHandler.session withContext:nil timeout:30.0 ];

Code for accepting invitation (Advertiser):

       - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser 
didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
    {
        ArrayInvitationHandler = [NSArray arrayWithObject:[invitationHandler copy]];

        // ask the user
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:peerID.displayName
                                  message:@"Would like to create a session with you"
                                  delegate:self
                                  cancelButtonTitle:@"Decline"
                                  otherButtonTitles:@"Accept", nil];
        [alertView show];

        if (alertViewResult)
        {
            void (^invitationHandler)(BOOL, MCSession *) = [ArrayInvitationHandler objectAtIndex:0];
            invitationHandler(YES, self.appDelegate.mpcHandler.session);


        }
    }

Any help is greatly appreciated!

Austin

Austin
  • 79
  • 1
  • 6

1 Answers1

0

I ran into a similar problem trying to use MPC. I created a custom class to handle all of the MPC connectivity details. While testing though, every time my advertiser would accept the invite, it would complain about wrong connection data and fail. I discovered that the problem was that I was vending out the MCPeerID object for my device from a class variable I created as below:

 static var peerObject : MCPeerID {
    return MCPeerID(displayName: deviceNameString)
 }

 lazy var sessionIVar = MCSession (peer: MyConnectivityClass.peerObject)

 func startAdvertisingForConnectivity () {
    advertiserService = MCNearbyServiceAdvertiser (peer: MyConnectivityClass.peerObject, discoveryInfo: nil, serviceType: "my-multipeer-connectivity-service-identifier")
 }

Then when I got an invitation I would initialize a MCSession object using the "peerObject" computed property and return it in the invitation handler, like this:

 func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Swift.Void) {
    invitationHandler(true, sessionIVar)
 }

I assumed that each time I called for "MyConnectivityClass.peerObject" it would give back an identical peerID because I was always initializing it with the same display name. It turns out that's not true. So when I was advertising I was using one peerID object and then when I was responding to the invitation, I was responding with a MCSession object that contained an entirely different peerID.

So the solution was to change the "MyConnectivityClass.peerObject" computed class property to a constant, or an Ivar, in my connection handler class. Like this:

 let peerObject : MCPeerID = MCPeerID(displayName: deviceNameString)

Then the rest of the code just worked because no matter how many times I called for the MCPeerID object, it was always the same. Looking back I don't know why I started out with it the way I did. :-)

Then in my connectivity class I archived and stored the MCPeerID objects for both the browser and the advertiser so that I could have the advertiser automatically accept the invitation for trusted MCPeerIDs. That's not possible if you create the MCPeerID object each time you use it, even if you always initialize it with the same DisplayName.

bdepaz
  • 434
  • 1
  • 3
  • 9