Search code examples
iosswiftcodabledecodablejsondecoder

Swift: Array of any does not conform to protocol 'Decodable'


I'm decoding a json response but I'm getting and array of different objects. Here is my implementation:

public struct MyDecodable: Decodable {
    public var id: Int
    public var name: String
    public var someData: [Any]
}

Here is my error:

enter image description here

My question to any of you is, how can I make this implementation conform to protocol Decodable?

I'll really appreciate your help


Solution

  • Decodable protocol requires an initializer with a decoder, like the documentation says :

    /// A type that can decode itself from an external representation.
    public protocol Decodable {
        /// Creates a new instance by decoding from the given decoder.
        ///
        /// This initializer throws an error if reading from the decoder fails, or
        /// if the data read is corrupted or otherwise invalid.
        ///
        /// - Parameter decoder: The decoder to read data from.
        init(from decoder: Decoder) throws
    }
    

    By default with simple types, or other Decodable implemented types, the initializer can be omitted because Swift can automatically map your JSON object to your Swift object.

    In your case, the Any type is not Decodable :

    Value of protocol type 'Any' cannot conform to 'Decodable', only struct/enum/class types can conform to protocols
    

    So, you should type your array with a specific generic type (it's the better solution), or either, write a specific decoding process in the decoding initializer :

    public struct MyDecodable: Decodable {
        public var id: Int
        public var name: String
        public var someData: [Any]
    
        enum CodingKeys: String, CodingKey {
            case id
            case name
            case someData
        }
    
        public init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(Int.self, forKey: .id)
            name = try container.decode(String.self, forKey: .name)
            // Do your stuff here to evaluate someData from your json
        }
    }
    

    More infos here (Swift4) : https://medium.com/swiftly-swift/swift-4-decodable-beyond-the-basics-990cc48b7375