2

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
    }
  ]
}
Bhavik Modi
  • 1,517
  • 14
  • 29
Okan
  • 410
  • 4
  • 10
  • 1
    Use Array not NSArray. What is the content of data (the array)? – Joakim Danielson May 15 '19 at 11:22
  • I tried it.When I use Array. I failed again. "Any" does not conform ...... same error. @JoakimDanielson – Okan May 15 '19 at 11:24
  • 1
    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 May 15 '19 at 11:25
  • The content of data is not constant. It can be everything. First index = Int, Second index = String, Third index = Object. – Okan May 15 '19 at 11:27

1 Answers1

1

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

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • The content of data is not constant. It can be everything. First index = Int, Second index = String, Third index = Object. – Okan May 15 '19 at 11:27
  • then `Codable` can't be used go with `JSONSerialization` – Shehata Gamal May 15 '19 at 11:28
  • I shared sample response. Is it impossible with Codable? – Okan May 15 '19 at 11:33
  • Yes, i know this solution but i have a lot of response like that. I need general thing. – Okan May 15 '19 at 11:38
  • I have not only DeviceInformation and Model. I have a lot of Model like that in NSArray. I need to find general thing. – Okan May 15 '19 at 11:39
  • 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 – Shehata Gamal May 15 '19 at 11:39
  • Yes, type is changing at every response and at every index. Okay, i understood. Thanks for help. – Okan May 15 '19 at 11:43
  • Can you add this comment on your post? For others?? @Sh_Khan – Okan May 15 '19 at 11:46
  • 1
    I know this way. But, all items in the array don't have the same contents. I shared the response, check it. @vadian – Okan May 15 '19 at 12:10
  • @Okan, if `data` content can be of different type you may try to use `Codable` `enum`. – user28434'mstep May 15 '19 at 12:30
  • @user28434 `enum` fits for 2 values , but if it exceeds that it will be a messy code with many switches around – Shehata Gamal May 15 '19 at 12:32
  • @Sh_Khan, wut? Each `enum` case is just for separation of different cases, and it should just contain a **single** associated value of some `Codable` type. Like `enum Datum: Codable { case int(Int); case string(String; case object(SomeObject) }` – user28434'mstep May 15 '19 at 12:34
  • i'm talking about checking the type in your posted comment you would do a switch – Shehata Gamal May 15 '19 at 12:36
  • @Sh_Khan, if you don't know the actual type you would "do a switch" anyways, only later in code. – user28434'mstep May 15 '19 at 13:01