Luda
Luda

Reputation: 7068

Decoding manually a non Codable property of a Codable class

ClassA conforming to Cadable and has a bunch of properties. One of them is a property of an already existing very complex ClassB that does not conform to Codable. Can I manually decode a non Codable property of a Codable class?

struct ClassA: Codable {

   let title: String?
   let subtitle: String?
   let property: ClassB?

    enum CodingKeys: String, CodingKey {
      case title
      case subtitle
      case property
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        title = try container.decode(String.self, forKey: .title)
        subtitle = try container.decode(String.self, forKey: .subtitle)
        let JSONString = ?
        property = ClassB.initWith(JSONString: JSONString)
  }

class ClassB: NSObject {

    // Already existing very complex ClassB implemenatation...
}

I get error:

Type 'ClassA' does not conform to protocol 'Encodable'

Upvotes: 1

Views: 674

Answers (2)

Max
Max

Reputation: 22325

Yes you can.

The error is that you're missing func encode(to encoder: Encoder) throws in ClassA. Codable = Encodable & Decodable, so it's trying to find a way to encode ClassA as well. ClassB isn't encodable so it can't do it automatically, and you haven't told it how to do it manually either.

If you don't need to encode ClassA instances, just make it Decodable. Otherwise implement the missing encode func.

Or just put in the work and make ClassB codable as well. You can use an extension to add it after the fact. If you don't want to do that either, a workaround I've used is to declare a small private codable struct inside ClassA like struct ClassBInfo: Codable. Use that to get the info you need, then read its properties to init ClassB.

Upvotes: 1

Yoel Jimenez del valle
Yoel Jimenez del valle

Reputation: 1278

try this

struct ClassA: Codable {

   let title: String?
   let subtitle: String?
   let property: ClassB?

    enum CodingKeys: String, CodingKey {
      case title
      case subtitle
      case property
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        title = try container.decode(String.self, forKey: .title)
        subtitle = try container.decode(String.self, forKey: .subtitle)
        let JSONString = ?
        property = ClassB.initWith(JSONString: JSONString)
  }

class ClassB: Codable {

    // Already existing very complex ClassB implemenatation...
}

Upvotes: 0

Related Questions