'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:
- Device A establishes a connection with Device B and sends data.
- Device B saves the
NWConnectioninformation of Device A. - 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.
init(host: NWEndpoint.Host, port: NWEndpoint.Port, using: NWParameters)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 |
|---|
