7
votes

I am having a struct which conforms to the protocol Codable. I am having a property of type [String: Any]?. But the codable doesn't allow me to use it. Saying the error

does not conform to protocol 'Decodable

1
You can’t have Any in your struct if you want to conform to CodableJoakim Danielson
Can you give more information about what you want to do with the JSON? There are different ways of doing this which have advantages and disadvantages.rpecka
I am having a struct as described below. struct A: Codable { let a: Int let b: [String: Any] } But it is throwing an error. As I said in the question.Sarath Kumar Rajendran
Replace the [String: Any] with a proper type that matches your meaning. [String: Any] means "a mapping of strings to literally any type that could ever exist." It is not possible to convert that to JSON (what would you do if the value were a CBPeripheral?) So redesign your struct to use the type you actually mean. (If you're uncertain what type you mean, that would be a good question for StackOverflow.)Rob Napier
Yes, I am uncertain about the data. The only thing which I know is that will be a dictionary (JSON).Sarath Kumar Rajendran

1 Answers

12
votes

Use the old JSONSerialization class to convert between Data and [String: Any] if you must. Data is Codable. You could also use another format, just as String. Note that swift is strongly typed, so using an enum with associated values is generally preferred over Any. If the intent is to actually write to the sever and not to local storage then you can also consider just forgetting about Codable and using JSONSerialization for the whole thing.

Example:

import UIKit
import PlaygroundSupport

struct A: Codable {
    let a: Int
    let b: [String: Any]

    enum CodingKeys: String, CodingKey {
        case a
        case b
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        a = try values.decode(Int.self, forKey: .a)
        let data = try values.decode(Data.self, forKey: .b)
        b = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(a, forKey: .a)
        let data = try JSONSerialization.data(withJSONObject: b, options: [])
        try container.encode(data, forKey: .b)
    }
}