tattn / MoreCodable

MoreCodable expands the possibilities of `Codable`.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Type 'Any' does not conform to protocol 'Decodable'

d-date opened this issue · comments

In DictionaryDecoder, we found some build errors, which are caused from the type 'Any' does not conform to protocol 'Decodable' . Please check and fix these if you don't mind.

open func container<Key: CodingKey>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
        let container = try lastContainer(forType: [String: Any].self)
        return KeyedDecodingContainer(KeyedContainer<Key>(decoder: self, codingPath: [], container: container)) // <- error: Type `Any` does not conform to protocol `Decodable`
    }

    open func unkeyedContainer() throws -> UnkeyedDecodingContainer {
        let container = try lastContainer(forType: [Any].self) // <- error: Type `Any` does not conform to protocol `Decodable`
        return UnkeyedContanier(decoder: self, container: container)
    }

...

func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
    decoder.codingPath.append(key)
    defer { decoder.codingPath.removeLast() }

     let value = try find(forKey: key)
     let dictionary = try decoder.unbox(value, as: [String: Any].self) // <- error: Type `Any` does not conform to protocol `Decodable`
     return KeyedDecodingContainer(KeyedContainer<NestedKey>(decoder: decoder, codingPath: [], container: dictionary))
}

func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
    decoder.codingPath.append(key)
    defer { decoder.codingPath.removeLast() }

     let value = try find(forKey: key)
     let array = try decoder.unbox(value, as: [Any].self) // <- error: Type `Any` does not conform to protocol `Decodable`
      return UnkeyedContanier(decoder: decoder, container: array)
}

So the workaround is to make Any into AnyDecodable so it ends up something like this:

public struct AnyDecodable : Decodable {
  
  let value :Any
  
  public init<T>(_ value :T?) {
    self.value = value ?? ()
  }
  
  public init(from decoder :Decoder) throws {
    let container = try decoder.singleValueContainer()
    
    if let string = try? container.decode(String.self) {
      self.init(string)
    } else if let int = try? container.decode(Int.self) {
      self.init(int)
    } else {
      self.init(())
    }
    // handle all the different types including bool, array, dictionary, double etc
  }
}

I got that code from this post: https://medium.com/@azamsharp/understanding-type-erasure-in-swift-2bf8fc530653 where they talk about this issue.

@d-date @garsdle Thanks for the issue and support!
Oh, conditional conformance seems to be causing a build error...

AnyDecodable is good idea! I'll refer to it in the future :D
This time, I fixed it in another way d8d69ff. But it is not cool, so I refactor it later.