2

During decoding of ClassA that conforms to Decodable, I would like to retrieve the value of one of the properties for custom decoding. How do I achieve that?

class ClassA: Decodable {

    let title: String?
    let data: MyCustomNotDecodableNSObject?

    private enum CodingKeys: String, CodingKey {
        case title
        case data
    }

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

        title = try? container.decode(String.self, forKey: .title)

        let dataRawValue = ? // somehow retrieve the raw value that coresponds to the key "data" (JSON string)
        let theData = MyCustomNotDecodableNSObject(rawData: dataRawValue)
        data = theData
    }
}

Example of parsed JSON:

{
    "classA" : {
         "title" = "a title"
         "data" : {
             "key1" : "value 1",
             "key2" : "value 2",
             "key3" : "value 3"
          }
} 

The thing I am after is:

"key1" : "value 1",
"key2" : "value 2",
"key3" : "value 3"

Please, do not suggest making MyCustomNotDecodableNSObject conform to Decodable protocol. This class cannot be modified.

Luda
  • 7,282
  • 12
  • 79
  • 139
  • Please add an example of input and output – vadian Jun 30 '19 at 09:31
  • Do you expect `dataRawValue` to be of type `Data`? – Sweeper Jun 30 '19 at 09:36
  • Hi, but why MyCustomNotDecodableNSObject should not be decodable? You can easily decode values like that if your type is conformed to decodable, `let dataRawValue = try? container.decode(MyCustomNotDecodableNSObject.self, forKey: .data)` – Andrew Jun 30 '19 at 09:40
  • @Andrew Please, do not suggest making MyCustomNotDecodableNSObject conform to Decodable protocol. This class cannot be modified. – Luda Jun 30 '19 at 10:55
  • Your update does not answer my question of "do you expect to get a `Data`? Or do you want to get it as a string?". – Sweeper Jun 30 '19 at 10:56
  • Possible duplicate of [How to decode a property with type of JSON dictionary in Swift 4 decodable protocol](https://stackoverflow.com/questions/44603248/how-to-decode-a-property-with-type-of-json-dictionary-in-swift-4-decodable-proto) – Luda Jun 30 '19 at 12:25
  • Added an answer where you can decode "Any".. – Brandon Jun 30 '19 at 23:08

1 Answers1

1

It is somewhat difficult to do this. One way I found is to first decode the part you want as a [String: Any], using the method described in this post. Then, convert that dictionary to Data using JSONSerialization, which is quite a long-winded way of doing things, but I couldn't find a better way.

if let dict = try container.decodeIfPresent([String: Any].self, forKey: .data) {
    let dataRawValue = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) // prettyPrinted is optional here
    data = MyCustomNotDecodableNSObject(rawData: dataRawValue)
} else {
    data = nil
}

If you actually want a String to pass into MyCustomNotDecodableNSObject.init, just call String.init(data:encoding:).

Extension from the linked post is needed!

Luda
  • 7,282
  • 12
  • 79
  • 139
Sweeper
  • 213,210
  • 22
  • 193
  • 313