1
votes

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'

2
It isn't clear what you mean by "manually decode". You can do for ClassB exactly what you did for classA, namely declare it Decodable and implement init(fromDecoder:) (and similarly on the Encodable side if you need it). But you cannot make ClassA Codable at all if it has a ClassB property and ClassB isn't Codable. - matt

2 Answers

1
votes

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.

0
votes

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...
}