2
votes

I am trying to transform "Object Mapper" to "Codable". My response which comes from service includes NSArray which includes custom objects. I need to use NSArray and NSDictionary in Codable Class. But, i failed.I tried to use third party library like AnyCodable, but, i failed again. I can't change the response on server side. It must come as Array. I must use Array. Do you have any suggestion or information?

class Person : Codable { //Error 1
  var name: String?
  var data: NSArray?

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

  func encode(to encoder: Encoder) throws {
      var container = encoder.container(keyedBy: CodingKeys.self)
      try container.encode(name, forKey: .name)
      try container.encode(data, forKey: .data) //Error 2
  }

  func decode(from decoder: Decoder) throws {
      let container = try decoder.container(keyedBy: CodingKeys.self)
      self.name = try container.decode(String.self, forKey: .name)
      self.data = try container.decode(NSArray.self, forKey: .data) //Error 3
  } 
}

Error 1: "Type 'Person' does not conform to protocol 'Decodable'"

Error 2: "Argument type 'NSArray' does not conform to expected type 'Encodable'"

Error 3: "Instance method 'decode(_:forKey:)' requires that 'NSArray' conform to 'Decodable'"

Sample response is here.All items in the array don't have the same contents. Every item in array has different type.

{
  "data": [
    {
      "languageCode": "EN",
      "deviceInformation": {
        "screenSize": "height:812.0 width:375.0",
        "connectionType": "wifi",
        "deviceType": "iPhone",
        "deviceCode": "D01D304C-D05C-4443-9A92-031C55D14XC7",
        "operatingSystemVersion": "12.2",
        "applicationVersion": "1.0"
      },
      "lastUpdatedParamDate": "13.05.2019 14:44:24",
      "skipOptionalUpdate": 0
    }
  ]
}
1
Use Array not NSArray. What is the content of data (the array)? - Joakim Danielson
I tried it.When I use Array<Any>. I failed again. "Any" does not conform ...... same error. @JoakimDanielson - Okan
Yes, you need give the exact type. You write "custom objects", of the same class or? You need to include the definition of that custom class as well. - Joakim Danielson
The content of data is not constant. It can be everything. First index = Int, Second index = String, Third index = Object. - Okan

1 Answers

1
votes

When you make it

var data: NSArray?

it's a bridged objective - c type that have Any as the type of elements and Any doesn't conform to Codable so explicitly make it the type like

var data:[SomeModel]

or use JSONSerialization instead


struct Root: Codable {
    let data: [Model]
}

struct Model: Codable {
    let languageCode: String
    let deviceInformation: DeviceInformation
    let lastUpdatedParamDate: String
    let skipOptionalUpdate: Int
}

struct DeviceInformation: Codable {
    let screenSize, connectionType, deviceType, deviceCode: String
    let operatingSystemVersion, applicationVersion: String
}

let eventData = try JSONDecoder().decode(Root.self, from: data) 

if you have more attributes you can add them , if some returns nil in some cases make them optional , but if the type changes then no way with Codable