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

Decode responses to Struct via Codable

Open kristoff-it opened this issue 8 years ago • 6 comments

At the moment objects coming in via the socket get decoded as [String: Any], and to obtain a struct from a response one has to manually implement something along the lines of init(dict: dataComingFromSocketIO) in which every single property has to be manually mapped.

Some answers on Stack overflow even suggest to serialize the Dictionary back to json and use another library to parse it back into a Struct using the Codable protocol, which is... not optimal.

Considering that communications through the socket come encoded as json, it seems plausible to inject the same behavior during the initial decoding step using the standard json decoder.

The interface could look something like this: func emit<U: Codable> (_ event: String, decodeAs: U, _ items: SocketData...)

Is there a reason why this might be harder than what it seems? Or maybe is someone already working on that?

If it's not too involved I might try to start working on a PR, let me know please. Thanks!

kristoff-it avatar Feb 15 '18 16:02 kristoff-it

Actually, data currently gets decoded as [Any], small inprecision on my part.

kristoff-it avatar Feb 16 '18 14:02 kristoff-it

It gets a bit more complicated since socket.io supports sending raw binary in objects at the application level. Internally it has to go through each object and remove the binary and add placeholders for them. So you would still have to handle this case.

nuclearace avatar Feb 19 '18 12:02 nuclearace

I see, I definitely don't know enough about how contents are framed to work on this. Maybe this feature should be kept in mind for when the project will undergo a big rewrite, as it seems to me that a cast to a struct is a fairly idiomatic use case for Swift.

kristoff-it avatar Feb 19 '18 13:02 kristoff-it

Right, this is why I introduced SocketData

nuclearace avatar Feb 19 '18 14:02 nuclearace

@nuclearace just a note that Swifts JSONEncoder has a provision for binary data via its dataEncodingStrategy field.

eddieSullivan avatar Apr 23 '19 18:04 eddieSullivan

I did this and it works fine for now

extension Encodable {
    func toJSONDict() -> [String: Any]? {
        do {
            let jsonData = try JSONEncoder().encode(self)
            return try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any]
        } catch {
            Log.error("Failed to convert \(Self.self) to JSON: \(error)")
            return nil
        }
    }
}
let joinData = JoinRoomModel(projectId: projectId, conversationId: conversationId)
if let jsonDict = joinData.toJSONDict() {
    socket?.emit(SocketEvent.joinRoom.rawValue, jsonDict)
}

FireLord avatar Apr 04 '25 16:04 FireLord