'How to create NWConnection

Premise

I'm using Apple's Network framework to create a peer-to-peer app. What I'm currently trying to do is:

  1. Device A establishes a connection with Device B and sends data.
  2. Device B saves the NWConnection information of Device A.
  3. Device B establishes a connection with Device A again using the saved MWConnection information and sends data.

I modelled off Apple's demo, which is essentially this source code here. Unlike Apple's demo, which establishes a single two-way connection and maintains that connection at all times, my app connects to multiple devices that can drop in and out of the connections at any time. This is why I want to be able to a) distinguish a specific device and b) initiate a new connection.

Problem

The problem I'm having is being able to reconstruct the NWConnection object using the information provided when a connection has been established. There are two ways of instantiating this object.

  1. init(host: NWEndpoint.Host, port: NWEndpoint.Port, using: NWParameters)
  2. init(to: NWEndpoint, using: NWParameters)

My attempts have been trying to gather the endpoint information like the host and the port while the connection with the desired device has been established and instantiate NWEndpoint to be used in NWConnection. But, I haven't been able to re-establish the connection thus far.

Following is the portion of the object that is used to initiate a connection. My full code is modified, but Apple's counterpart can be seen here.

class PeerConnection {
    
    weak var delegate: PeerConnectionDelegate?
    weak var statusDelegate: StatusDelegate?
    var connection: NWConnection?
    let initiatedConnection: Bool
    
    init(endpoint: NWEndpoint, interface: NWInterface?, passcode: String, delegate: PeerConnectionDelegate) {
        self.delegate = delegate
        self.initiatedConnection = true
        
        let connection = NWConnection(to: endpoint, using: NWParameters(passcode: passcode))
        self.connection = connection
        
        startConnection()
    }
    
    init(connection: NWConnection, delegate: PeerConnectionDelegate) {
        self.delegate = delegate
        self.connection = connection
        self.initiatedConnection = false
        
        startConnection()
    }

    // Handle starting the peer-to-peer connection for both inbound and outbound connections.
    func startConnection() {
        guard let connection = connection else {
            return
        }
        
        connection.stateUpdateHandler = { newState in
            switch newState {
                case .ready:
                    print("\(connection) established")
                    
                    // When the connection is ready, start receiving messages.
                    self.receiveNextMessage()
                    
                    // Notify your delegate that the connection is ready.
                    if let delegate = self.statusDelegate {
                        delegate.showConnectionStatus(.connectionSuccess("Connection Success"))
                    }
                case .failed(let error):
                    print("\(connection) failed with \(error)")
                    
                    // Cancel the connection upon a failure.
                    connection.cancel()
                    
                    // Notify your delegate that the connection failed.
                    if let delegate = self.statusDelegate {
                        delegate.showConnectionStatus(.connectionFail("Connection Fail"))
                    }
                default:
                    break
            }
        }
        
        // Start the connection establishment.
        connection.start(queue: .main)
    }
}

This is how I receive data when another device sends it.

func receiveNextMessage() {
    guard let connection = connection else {
        return
    }
    
    /// Has to call itself again within the closure because the maximum message is once.
    connection.receiveMessage { (content, context, isComplete, error) in
        // Extract your message type from the received context.
        if let message = context?.protocolMetadata(definition: GameProtocol.definition) as? NWProtocolFramer.Message {
            self.delegate?.receivedMessage(content: content, message: message, connection: connection)
        }
        if error == nil {
            // Continue to receive more messages until you receive and error.
            self.receiveNextMessage()
        }
    }
}

Finally, following is how I attempt to reconstruct MWConnection:

func receivedMessage(content: Data?, message: NWProtocolFramer.Message, connection: NWConnection) {
    switch(connection.endpoint) {
        case .hostPort(let host, let port):
            

            /// first attempt
            let endpoint = NWEndpoint.hostPort(host: host, port: port)
            let newConnection = PeerConnection(endpoint: endpoint, interface: nil, passcode: passcode, delegate: self)
            
            /// second attempt
            let connection = NWConnection(host: host, port: port, using: NWParameters(passcode: passcode))
            let newConnection = PeerConnection(connection: connection, delegate: self)

            
        default:
            break
    }
}

NWConnection is instantiated inside initializer of PeerConnection.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source