socketio / socket.io-client-swift

Other
5.21k stars 841 forks source link

SocketClient deinit never called. #1417

Open JimWest93 opened 2 years ago

JimWest93 commented 2 years ago

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
nuclearace commented 2 years ago

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

JimWest93 commented 2 years ago

Nope

nuclearace commented 2 years ago

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

JimWest93 commented 2 years ago

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 commented 2 years ago
Снимок экрана 2022-07-12 в 21 19 36
nuclearace commented 2 years ago

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 commented 2 years ago

Ah, so it's something in the Acks.

nuclearace commented 2 years ago

What does your ack callback look like?

nuclearace commented 2 years ago

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.

JimWest93 commented 2 years ago
    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
            }
        }