V. Khuraskin
V. Khuraskin

Reputation: 89

ActionCable answer parse

I make iOS app that has a chats. It's built on ActionCable. I use ActionCableClient library to work with it. Everything works great. The only problem with parsing a received message. It has type Any:

Optional({
    data =     {
        author =         {
            "avatar_url" = "<null>";
            name = "\U0410\U043b\U043b\U0430";
            uid = "eb1b5fe6-5693-4966-bf72-a30596353677";
        };
        "created_at" = "1598446059.511528";
        file = "<null>";
        image = "<null>";
        quote = "<null>";
        status = red;
        text = "test message";
        type = OperatorMessage;
        uid = "30b4d5ed-639d-46fb-9be3-b254de3b1203";
    };
    type = "operator_message";
})

And cast Any type to Data doesn't work. I can't JSONDecode it through this. I can get String out of it.

String(describing: data)

But I don't know how to use it anymore. How do you get a data model out of it?

Upvotes: 0

Views: 55

Answers (1)

Larme
Larme

Reputation: 26066

That's the print of a NSDictionary. So you can do:

guard let dict = that as? NSDictionary else { return }

or, in a more Swift way:

guard let dict = that as? [String: Any] else { return }  

And for instance, retrieving some values:

let type = dict["type"] as? String
if let subdata = dict["data"] as? [String: Any] {
    let text = subdata["text"] as? String
    let kid = subdata["uid"] as? String
    ...
}

If you want to retrieve (NS)Data back, you can use JSONSerialization to transform it back, and use a JSONDecoder, but since there was already a

Data ----(through JSONSerialization)----> Dictionary

Going back to Data would mean

Data ----(through JSONSerialization)----> Dictionary ----(through JSONSerialization)----> Data ----(through JSONDecoder)----> CustomStruct

While, you could have a CustomStruct init with your dictionary.

So if you have a codable struct:

struct Response: Codable {
    let data: CustomData
    let type: String
}

struct CustomData: Codable {
    let uid: String
    let text: String
    ...
}

The quickest way would be then to add:

extension Response {
    init?(dict: [String;: Any] {
        guard let type = dict["type"] as? String?
               let data = dict["data"] as? [String: Any] else { return nil }
        self.type = type
        self.data = data
    }
}

extension CustomData {
    init?(dict: [String;: Any] {
        guard let uid = dict["did"] as? String?
               let text = dict["text"] as? String else { return nil }
        self.uid = uid
        self.text = text
        ...
    }
}

Upvotes: 1

Related Questions