NWConnection's connection.receiveMessage method gets breakpoint hit but callback not entered

I have a NWBrowser and a NWConnection on my iPhone 7+ (real device) that sends out some data. On the simulator I have a NWListener and a NWConnection that receives the data.

Inside the NWListener class named PeerListener, inside the listener.newConnectionHandler callback I have a delegate to create a NWConnection that gets hit multiple times when I put a break point on it. This results in the NWConnection's connection.stateUpdateHandler printing out the following multiple times below:

Code Block
// these are all .preparing and .ready cases
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established


After the last print statement, which is .ready, the connection is sent over to the VC via a delegate where connection.receiveMessage runs. I put a break point on it, it gets hit, but the call back is never entered.

I'm not sure what the problem is because the connection is definitely happening between the device and simulator, all the correct methods are hit (unfortunately multiple times), but the callback is never entered. What is the problem here?

NWListener

Code Block
protocol PeerListenerDelegate: class {
    func createNewIncoming(_ connection: NWConnection)
}
class PeerListener {
    weak var delegate: PeerListenerDelegate?
    fileprivate var listener: NWListener?
init () {
        do {
            let tcpOptions = NWProtocolTCP.Options()
            tcpOptions.enableKeepalive = true
            tcpOptions.keepaliveIdle = 2
            let parameters = NWParameters(tls: nil, tcp: tcpOptions)
            parameters.includePeerToPeer = true
            listener = try NWListener(using: parameters)
            listener?.service = NWListener.Service(name: "MyName", type: "_myApp._tcp")
            startListening()
        } catch let error as NSError {
            print("Failed to create listener", error.debugDescription)
        }
    }
fileprivate func startListening() {
        guard let listener = listener else { return }
        listener.stateUpdateHandler = { [weak self](newState) in
            switch newState {
case .setup: print("listener setup")
            case .ready: print("Listener ready on \(String(describing: listener.port))")
            case .cancelled: print("listener cancelled")
            case .failed(let error):
                if error == NWError.dns(DNSServiceErrorType(kDNSServiceErr_DefunctConnection)) {
                    listener.cancel()
                    self?.startListening()
                } else {
                    print(error.debugDescription)
                    listener.cancel()
                }
            default:break
            }
        }
        receivedNewConnectionFrom(listener)
        listener.start(queue: .main)
    }
fileprivate func receivedNewConnectionFrom(_ listener: NWListener) {
        listener.newConnectionHandler = { [weak self](newConnection) in
            self?.delegate?.createNewIncoming(newConnection)
        }
    }
}

VC that initializes the Listener, connection.receiveMessage is in here, last function at the bottom, line 23

Code Block
class ViewController: UIViewController {
fileprivate var listener: PeerListener?
fileprivate var connectionIncoming: ConnectionIncoming?
override func viewDidLoad() {
        super.viewDidLoad()
listener = PeerListener()
        listener?.delegate = self
}
// 1. PeerListenerDelegate to create NWConnection object
func createNewIncoming(_ connection: NWConnection) {
        self.connectionIncoming = ConnectionIncoming(connection:connection, delegate: self)
    }
// 2. ConnectionIncomingDelegate to receive data from connection object
func receivedIncoming(_ connection: NWConnection) {
        connection.receiveMessage { [weak self](data, context, isComplete, error) in
            print(" *** callback entered * THIS NEVER GETS HIT *** ")
            if let err = error {
                print("Recieve error: \(err.debugDescription)")
                return
            }
            if isComplete {
                print("Receive is complete")
                if let data = data, !data.isEmpty {
self?.received(data, from: connection)
                }
            } else {
                print("Not Complete")
            }
        }
    }
}


NWConnection
Code Block
protocol ConnectionIncomingDelegate: class {
    func receivedIncoming(_ connection: NWConnection)
}
class ConnectionIncoming {
    weak var delegate: ConnectionIncomingDelegate?
    private var connection: NWConnection?
    init(connection: NWConnection, delegate: ConnectionIncomingDelegate) {
        self.delegate = delegate
        self.connection = connection
        startConnection()
    }
    func startConnection() {
        guard let connection = connection else { return }
        connection.stateUpdateHandler = { [weak self](nwConnectionState) in
            switch nwConnectionState {
case .preparing: print("Connection preparing")
            case .setup: print("Connection setup")
            case .waiting(let error): print("Connection waiting: ", error.debugDescription)
            case .ready:
                print("Connection established")
                self?.delegate?.receivedIncoming(connection)
            case .failed(let error):
                print("Connection failed: ", error.debugDescription)
                connection.cancel()
            default:break
            }
        }
        connection.start(queue: .main)
    }
}

Answered by lance145 in 652188022
I found the answer to my problem here

@eskimo said:

. TCP is not a message-oriented protocol, and thus 
Code Block
receiveMessage(…)

doesn’t make any sense [1]. What you want is 
Code Block
receive(minimumIncompleteLength:maximumLength:completion:)


And he is 100% correct, as soon as I changed signatures, the callback was entered:

Code Block
connection.receive(minimumIncompleteLength: 1, maximumLength: 8192) { [weak self](data, context, isComplete, error) in
    print("\n*** call back entered *** ")
    if let err = error {
        print("Recieve error: \(err.localizedDescription)")
        return
    }
    print("databytes", data?.count as Any)
    if let data = data, !data.isEmpty {
        print("Receive is complete")
        self?.received(data, from: connection)
    }
}


The multiple calls is still happening be that's another question that I'll ask in a different post.

PS I don't know why I have 3 different usernames under the same account

lsamaria is the same person as ohmannnnnn who is the same person as lance145
UPDATE

I couldn't add this to the question because the Edit button somehow disappeared. This doesn't resolve the call back problem from my question but it did stop the multiple print statements however with a caveat.

I followed an answer in this thread from @meaton. Inside the NWListener class he used a bool property, private var didConnectionSetup: Bool = false, to stop listener.newConnectionHandler from getting called multiple times. It did work to stop the print statements for the firs device but the caveat is when another device (simulator) came on line and its NWBrowser was found, the bool property was stuck on true so delegate?.createNewIncoming never ran. I tried several things to change it like setting didConnectionSetup = false right afterwards but the print statement problem started all over again.

Code Block
private var didConnectionSetup: Bool = false
listener.newConnectionHandler = { [weak self](newConnection) in
guard let safeSelf = self else { return }
if safeSelf.didConnectionSetup { return }
safeSelf.didConnectionSetup = true
self?.delegate?.createNewIncoming(newConnection) // once any new device is found/browsed this never runs
}


this didn't work, print problem was still in effect on the first device and all subsequent devices:

Code Block
listener.newConnectionHandler = { [weak self](newConnection) in
guard let safeSelf = self else { return }
if safeSelf.didConnectionSetup { return }
safeSelf.didConnectionSetup = true
self?.delegate?.createNewIncoming(newConnection)
safeSelf.didConnectionSetup = false
}

Accepted Answer
I found the answer to my problem here

@eskimo said:

. TCP is not a message-oriented protocol, and thus 
Code Block
receiveMessage(…)

doesn’t make any sense [1]. What you want is 
Code Block
receive(minimumIncompleteLength:maximumLength:completion:)


And he is 100% correct, as soon as I changed signatures, the callback was entered:

Code Block
connection.receive(minimumIncompleteLength: 1, maximumLength: 8192) { [weak self](data, context, isComplete, error) in
    print("\n*** call back entered *** ")
    if let err = error {
        print("Recieve error: \(err.localizedDescription)")
        return
    }
    print("databytes", data?.count as Any)
    if let data = data, !data.isEmpty {
        print("Receive is complete")
        self?.received(data, from: connection)
    }
}


The multiple calls is still happening be that's another question that I'll ask in a different post.

PS I don't know why I have 3 different usernames under the same account

lsamaria is the same person as ohmannnnnn who is the same person as lance145
The link I posted in accepted answer is wrong. Here is the correct link

I couldn't add this to the question because the Edit button somehow
disappeared.

That’s expected. See this thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Here is the reason for the the multiple call problem, which isn't a problem, as explained by @eskimo here:

Apple’s connect-by-name API uses a fancy algorithm to run multiple connections in parallel to see which one connects first (see RFC 8305 for some background on this)




NWConnection's connection.receiveMessage method gets breakpoint hit but callback not entered
 
 
Q