swiftsocket / SwiftSocket

The easy way to use sockets on Apple platforms
BSD 3-Clause "New" or "Revised" License
1.68k stars 401 forks source link

Listening to incoming messages in another thread #107

Open Lulli4444 opened 7 years ago

Lulli4444 commented 7 years ago

Hi, I need my client to listen to incoming messages from the server. This is the code I've written: ... // Connection successful 🎉 case .success: print("--> Connected: waiting for a message..") sleep(1); self.connected = true self.sockTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.readSocket), userInfo: nil, repeats: true) break ...

func readSocket(){ if client != nil { if let data = client.read(1024,timeout: 5) { ...

The problem is that my whole app "freeze" every 5 seconds. I suppose that it is listening for messages, but obviously I don't want this behaviour. I've read to dispatch the reading to another thread, but I don't know how to do it. Could you please help me? Thanks!

xoniq commented 7 years ago

Late response, but still useful.

Define some variables within the class

    var connected = false
    var client: TCPClient? = nil

    var readingWorkItem: DispatchWorkItem? = nil
    var readingQueue = DispatchQueue(label: "Socket connections for reading")

Call this after the connection has been made:

connected = true
pollForResponse(for: client!)

Handle the data feed in a loop in a background process:

    var message = ""

    /// Handle message coming from the reading part
    func handleMessage(){
        let str = self.message

        print(str) // Do whatever you want with the response message

        // Reset message
        self.message = ""
    }

    /// Handles readings in the background
    ///
    /// - Parameter client: client with active connection
    func pollForResponse(for client: TCPClient){
        if(connected){
            readingWorkItem = DispatchWorkItem {
                guard let item = self.readingWorkItem else { return }

                // read incoming characters one at a time and add to message
                while !item.isCancelled {
                    guard let d = client.read(1, timeout: 1) else { continue }

                    let c = String(bytes: d, encoding: .utf8)
                    self.message += c!

                    if (c == "\n") {        // '\n'
                        self.handleMessage()
                    }
                }
            }
            readingQueue.async(execute: readingWorkItem!)
        }
    }
nneuberger1 commented 6 years ago

If it helps I wrapped my entire sending of a request and reading the response into it's own background async call. This eliminated the application hang. Originally the code that executed was on the main thread.

DispatchQueue.global(qos: .background).async { // add your code here. }