socket.io-client-swift icon indicating copy to clipboard operation
socket.io-client-swift copied to clipboard

SocketClient deinit never called.

Open JimWest93 opened this issue 3 years ago • 10 comments

Hello! Can you please tell me how to destroy the socket client? This code doesn't help. There are no strong references to the socket in the code. Thanks!

   socketManager?.setConfigs([.reconnects(false)])
    socketClient?.disconnect()
    if socketClient != nil {
        socketManager?.removeSocket(socketClient!)
        socketClient = nil
    }
    socketManager = nil
Снимок экрана 2022-07-12 в 13 25 54 Снимок экрана 2022-07-12 в 13 26 54

JimWest93 avatar Jul 12 '22 10:07 JimWest93

Are you capturing a strong reference to your client in a handler somewhere?

nuclearace avatar Jul 12 '22 17:07 nuclearace

Nope

JimWest93 avatar Jul 12 '22 17:07 JimWest93

Could you turn on logs and post the logs for the manager/client when it's trying to disconnect?

nuclearace avatar Jul 12 '22 18:07 nuclearace

Client: 2022-07-12 21:15:04.123333+0300 -[15227:165565] LOG SocketIOClient{/chat}: Closing socket 2022-07-12 21:15:04.123745+0300 -[15227:165565] LOG SocketIOClient{/chat}: Disconnected: Namespace leave 2022-07-12 21:15:04.124176+0300 -[15227:165565] LOG SocketIOClient{/chat}: Handling event: statusChange with data: [disconnected, 1] 2022-07-12 21:15:04.124587+0300 -[15227:165565] LOG SocketIOClient{/chat}: Handling event: disconnect with data: ["Namespace leave"]

Manager: 2022-07-12 21:16:35.673777+0300 -[15227:165565] LOG SocketManager: Manager is being released

JimWest93 avatar Jul 12 '22 18:07 JimWest93

Снимок экрана 2022-07-12 в 21 19 36

JimWest93 avatar Jul 12 '22 18:07 JimWest93

This simple example doesn't show the manager or engine holding a strong reference. So would either be something on your end, on something involving ACKs, or more complex example.

let manager: SocketManager
var socket2: SocketIOClient! = manager.socket(forNamespace: "/swift")

func addHandlers(_ socket: SocketIOClient) {
    socket.on(clientEvent: .connect) {[weak socket] data, ack in
        guard let nsp = data[0] as? String else { fatalError("Should have namespace") }
        guard let socket = socket else {
            return
        }
        print("In namespace: \(nsp)")
        print(socket.sid)
        manager.disconnectSocket(socket)
        manager.removeSocket(socket)
        socket2 = nil
    }
}

socket.connect(withPayload: ["hello": "world"], timeoutAfter: 3) {[weak socket] in
    print("failed to connect")
}

2022-07-12 14:23:25.827 Runner[28905:4697677] LOG SocketIOClient{/swift}: Socket connected 2022-07-12 14:23:25.827 Runner[28905:4697677] LOG SocketIOClient{/swift}: Handling event: statusChange with data: [connected, 3] 2022-07-12 14:23:25.827 Runner[28905:4697677] LOG SocketIOClient{/swift}: Handling event: connect with data: ["/swift", ["sid": rd3gJTYUfDNo9Hi1AAAH]] 2022-07-12 14:23:25.827 Runner[28905:4697677] LOG SocketIOClient{/swift}: Disconnected: Namespace leave 2022-07-12 14:23:25.828 Runner[28905:4697715] LOG SocketEngine: Writing poll: 1/swift, has data: false 2022-07-12 14:23:25.828 Runner[28905:4697677] LOG SocketIOClient{/swift}: Handling event: statusChange with data: [disconnected, 1] 2022-07-12 14:23:25.828 Runner[28905:4697715] LOG SocketEnginePolling: Sending poll: 1/swift, as type: 4 2022-07-12 14:23:25.828 Runner[28905:4697677] LOG SocketIOClient{/swift}: Handling event: disconnect with data: ["Namespace leave"] 2022-07-12 14:23:25.828 Runner[28905:4697715] LOG SocketEnginePolling: Created POST string: 41/swift, 2022-07-12 14:23:25.828 Runner[28905:4697677] LOG SocketIOClient{/swift}: Client is being released


CFRunLoopRun()

nuclearace avatar Jul 12 '22 18:07 nuclearace

Ah, so it's something in the Acks.

nuclearace avatar Jul 12 '22 18:07 nuclearace

What does your ack callback look like?

nuclearace avatar Jul 12 '22 18:07 nuclearace

Hmm, I wonder if it has to with this bit of code:


    /// Completes an emitWithAck. If this isn't called, the emit never happens.
    ///
    /// - parameter seconds: The number of seconds before this emit times out if an ack hasn't been received.
    /// - parameter callback: The callback called when an ack is received, or when a timeout happens.
    ///                       To check for timeout, use `SocketAckStatus`'s `noAck` case.
    @objc
    public func timingOut(after seconds: Double, callback: @escaping AckCallback) {
        guard let socket = self.socket, ackNumber != -1 else { return }

        socket.ackHandlers.addAck(ackNumber, callback: callback)
        socket.emit(items, ack: ackNumber, binary: binary)

        guard seconds != 0 else { return }

        socket.manager?.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {[weak socket] in
            guard let socket = socket else { return }

            socket.ackHandlers.timeoutAck(self.ackNumber)
        }
    }

Where it doesn't take a weak reference to self... Let me create a fix for that. I can try to put up a beta/patch soonish. Or you could try dev branch with change if possible.

nuclearace avatar Jul 12 '22 18:07 nuclearace

    client.emitWithAck("sendMessage", with: [["body": SomeText,
                                              "timestamp": SomeDate,
                                              "attachments": [],
                                              "tags": someTags]])
        .timingOut(after: 0) { [weak self] data in
            guard let self = self else { return }
            switch self.someFunc(data: data) {
            case let .success(): doSomething
            case .failure: doSomething2
            }
        }

JimWest93 avatar Jul 12 '22 18:07 JimWest93