0 Replies
      Latest reply on Oct 8, 2018 7:10 PM by igorland
      igorland Level 1 Level 1 (0 points)

        Hi.

         

        I have three problems implementing the MultipeerConnectivity framework.

         

        1) I am trying to connect three players to one MCSession. Every action that one peer does should be repeated by other peers. If I connect like this:

         

        A (iPad device) -> C (Simulator)

        B (iPhone device) -> C

         

        all actions performed by A and B are received by in C. However, when A is advertising and I connect B and C to A, whatever I do on B is not repeated on C (my Simulator). How to ensure that messages are sent all directions (three-way or four way)?

         

        2) Whenever one peer leaves the session, I am trying to reconnect the same peer to the same MCSession, but it never does. Why is this?

         

        3) If I disconnect peer A that was originally browsing and to which other peers connected, peer B starts crashing with the following message: "message sent to deallocated instance <MCPEERID A>" whenever I do any actions on it. Is there a way to preserve the session and other peers if they joined the peer that left?

         

        This is my class ConnectionManager class

         

        import Foundation
        import MultipeerConnectivity
        
        protocol ConnectionManagerDelegate
        {
            func foundPeer()
            func lostPeer(peerID: String)
            func invitationWasReceived(fromPeer: String)
            func connectedWithPeer(peerID: MCPeerID)
        }
        
        class ConnectionManager : NSObject, MCSessionDelegate, MCNearbyServiceBrowserDelegate, MCNearbyServiceAdvertiserDelegate, StreamDelegate
        {
        
            var delegate: ConnectionManagerDelegate?
            private let CONNECTION_SERVICE_TYPE = "play-service"
            public var session: MCSession!
            public var peer: MCPeerID!
            public var browser: MCNearbyServiceBrowser!
            public var advertiser: MCNearbyServiceAdvertiser!
            public var foundPeers = [MCPeerID]()
            public var invitationHandler: ((Bool, MCSession?)->Void)!
            var outputStream:OutputStream?
           
           
            override init()
            {
                super.init()
                peer = MCPeerID(displayName: UIDevice.current.name)
               
                session = MCSession(peer: peer, securityIdentity: nil, encryptionPreference: MCEncryptionPreference.optional)
                session.delegate = self
               
                browser = MCNearbyServiceBrowser(peer: peer, serviceType: CONNECTION_SERVICE_TYPE)
                browser.delegate = self
               
                advertiser = MCNearbyServiceAdvertiser(peer: peer,discoveryInfo: nil,serviceType: CONNECTION_SERVICE_TYPE)
                advertiser.delegate = self
            }
           
            deinit
            {
                browser.stopBrowsingForPeers()
                advertiser.stopAdvertisingPeer()
            }
           
        
            func browser(_ browser: MCNearbyServiceBrowser,
                         foundPeer peerID: MCPeerID,
                         withDiscoveryInfo info: [String : String]?)
            {
                foundPeers.append(peerID)
                delegate?.foundPeer()
            }
           
           
            func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID)
            {
                for (index, aPeer) in foundPeers.enumerated()
                {
                    if aPeer == peerID
                    {
                        foundPeers.remove(at: index)
                        break
                    }
                }
               
                delegate?.lostPeer(peerID: peerID.displayName)
            }
           
        
            func browser(_ browser: MCNearbyServiceBrowser,
                         didNotStartBrowsingForPeers error: Error)
            {
                print("DID NOT START BROWSING FOR PEERS",error.localizedDescription)
            }
           
        
            func advertiser(_ advertiser: MCNearbyServiceAdvertiser,
                            didReceiveInvitationFromPeer peerID: MCPeerID,
                            withContext context: Data?,
                            invitationHandler: @escaping (Bool, MCSession?) -> Void)
            {
                self.invitationHandler = invitationHandler
                delegate?.invitationWasReceived(fromPeer: peerID.displayName)
            }
           
        
            func advertiser(_ advertiser: MCNearbyServiceAdvertiser,
                            didNotStartAdvertisingPeer error: Error)
            {
                print("DID NOT START ADEVRTISING FOR PEERS",error.localizedDescription)
            }
           
           
            func session(_ session: MCSession,
                         peer peerID: MCPeerID,
                         didChange state: MCSessionState)
            {
                switch state
                {
                case MCSessionState.connected:
                    delegate?.connectedWithPeer(peerID: peerID)
                    startSession(peer: peerID)
        
                case MCSessionState.connecting:
                    print("Connecting to session: \(session)")
                   
                case MCSessionState.notConnected:
                    session.disconnect()
                    print("NOT connected to session: \(session)")
                   
                default:
                    print("Did not connect to session: \(session)")
                    stopSession()
                }
            }
           
        
            func session(_ session: MCSession,
                         didReceiveCertificate certificate: [Any]?,
                         fromPeer peerID: MCPeerID,
                         certificateHandler: @escaping (Bool) -> Void)
            {
                certificateHandler(true)
            }
           
           
            func startSession(peer peerID: MCPeerID)
            {
               
                do
                {  
                    if outputStream == nil
                    {
                        try outputStream = self.session.startStream(withName: "stream", toPeer: peerID)
                    }
                   
                    if let outputStream = outputStream
                    {
                        outputStream.delegate = self
                        outputStream.schedule(in: RunLoop.main, forMode:RunLoopMode.defaultRunLoopMode)
                        outputStream.open()
                    }
                }
                catch let error
                {
                    print("ERROR STARTING STREAM IN SESSION: \(error)")
                }
            }
           
        
            func stream(_ aStream: Stream, handle eventCode: Stream.Event)
            {
                switch(eventCode)
                {
                    case Stream.Event.hasBytesAvailable:
                        print("--STREAM EVENT HAS BYTES AVAILABLE--")
                        processInput(from: aStream)
                        break
        
                    case Stream.Event.hasSpaceAvailable:
                        print("--STREAM EVENT HAS SPACE AVAILABLE--")
                        break
                   
                    case Stream.Event.endEncountered:
                        print("--STREAM EVENT END ENCOUNTERED--")
                        break
                   
                    case Stream.Event.errorOccurred:
                        print("--STREAM EVENT ERROR OCCURRED--")
                        break
        
                    default:
                        print("--STREAM EVENT DEFAULT--")
                        break
                }
               
            }
        
            func stopSession()
            {
                closeConnection()
            }
        
        
            func closeConnection()
            {
                if(self.outputStream != nil)
                {
                    self.outputStream?.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
                    self.outputStream?.close()
                    self.outputStream = nil;
                }
                if(session != nil)
                {
                    session.disconnect()
                }
            }
        
        
            func sendDataToPeer()
            {
                if session.connectedPeers.count > 0
                {
                    let message = "This is a string test"
                    let data = NSKeyedArchiver.archivedData(withRootObject: message) //this is a NSData instance. Could be any NSData, as a serialized object, for example.
        
                    if let outputStream = outputStream
                    {
                        _ = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) }
                    }
                }
            }
           
            func processInput(from aStream: Stream)
            {
                let input = aStream as! InputStream
                var buffer = [UInt8](repeating: 0, count: 1024) //allocate a buffer. The size of the buffer will depended on the size of the data you are sending.
                let bytesRead = input.read(&buffer, maxLength:buffer.count) // Read buffer
               
                if (bytesRead>0)
                {
                    let dataString = NSData(bytes: &buffer, length: bytesRead)
                    let message = NSKeyedUnarchiver.unarchiveObject(with: dataString as Data) as! String //deserializing the NSData
                    print("STREAM: ",message)
                }
                else if (bytesRead < 0)
                {
                    print("Input stream has less than 0 bytes")
                   
                    // Close connection
                    //stopSession() TO DO!!! Disabled for now. Should the session continue?
                }
                else if bytesRead == 0
                {
                    print("Input stream has 0 bytes")
                }
            }
           
            func session(_ session: MCSession,
                         didReceive stream: InputStream,
                         withName streamName: String,
                         fromPeer peerID: MCPeerID)
            {
               
                if streamName == "stream"
                {
                    stream.delegate = self
                    stream.schedule(in: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
                    stream.open()
                }
            }
        }

        Thank you!