MultipeerConnectivity: three-way communication, reconnecting a peer, keeping the session

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!