I have the following NWListener. I am to listen only while the app is in the foreground, and re-listen when it come back from background. However I call my stop() function and if I call start() subsequently it fils. Also if the app is terminated (in debugger or task manager) I cannot launch the app again for ~5 seconds because the listen() will fail.
{
self.port = NWEndpoint.Port(rawValue: port)!
listenerState = .cancelled
self.eventHandler = handler
let parameters = NWParameters(tls: nil)
parameters.allowLocalEndpointReuse = true
parameters.includePeerToPeer = true
let wsOptions = NWProtocolWebSocket.Options()
wsOptions.autoReplyPing = true
parameters.defaultProtocolStack.applicationProtocols.insert(wsOptions, at: 0)
do {
listener = try NWListener(using: parameters, on: self.port)
listener!.stateUpdateHandler = self.stateDidChange(to:)
listener!.newConnectionHandler = self.didAccept(nwConnection:)
} catch {
print(#function, error)
}
deinit {
stop()
}
func start() throws {
print("Server starting...")
listener!.stateUpdateHandler = self.stateDidChange(to:)
listener!.newConnectionHandler = self.didAccept(nwConnection:)
listener!.start(queue: .main)
print("Server started.")
eventHandler()
}
func stop() {
self.listener!.stateUpdateHandler = nil
self.listener!.newConnectionHandler = nil
self.listener!.cancel()
print("Server cancelled")
connection?.stop()
connection?.didStopCallback = nil
connection = nil
eventHandler()
}
When it fails, it logs a backgrace (logs below) however there is no way for me to know it has failed. there is no NWListner.state variable, but there is a stateDidChange() handler which can only be called by the framework when the state change occurs however having been backgrounded, the last reported state is not valid.
There's a couple issues here
- I cannot quickly cancel() and listen() on the same port (this seems to be unique to swift as a native implementation works fine)
- There is no
state
variable to check. - I get a stacktrace dumped to the console rather than some catchable error. So My app has no way to know that the listen() failed.
Server starting...
2020-08-12 16:29:42.476799-0400 rfa-ios-native[821:464825] nw listener set queue Error in client: nw listener set queue called after nw listener start
2020-08-12 16:29:42.480218-0400 rfa-ios-native[821:464825] nw listener set queue Error in client: nw listener set queue called after nw listener start, dumping backtrace:
[arm64] libnetcore-1880.100.30
0 libnetwork.dylib 0x000000019218b060 _ nw create backtrace string + 120
1 libnetwork.dylib 0x00000001920a68bc nw listener set queue + 228
2 libswiftNetwork.dylib 0x00000001c6556e74 $s7Network10NWListenerC5start5queueySo012OS dispatch D0C tF + 56
...
Server started.
2020-08-12 16:29:42.482909-0400 rfa-ios-native[821:464835] nw listener start block invoke [L1] In wrong state for start
2020-08-12 16:29:42.483533-0400 rfa-ios-native[821:464835] nw listener start block invoke [L1] In wrong state for start, dumping backtrace:
[arm64] libnetcore-1880.100.30
0 libnetwork.dylib 0x000000019218b060 _ nw create backtrace string + 120
1 libnetwork.dylib 0x00000001920a89e8 6B86071A-0DFC-3EFD-A798-615EC6A7D591 + 3578344
2 libdispatch.dylib 0x000000010068dd10 dispatch call block and_release + 32
...