Search code examples
iosarraysjsonswiftobjectmapper

Map JSON either as Array or Object


I have json that shows me sometimes array sometimes simple object

"ownersPeriod" : [
        {
          "dateTo" : "2013-06-17",
          "dateFrom" : "2012-09-15"
        },
        {
          "dateTo" : "2016-06-30",
          "dateFrom" : "2013-06-17"
        },
        {
          "dateTo" : "",
          "dateFrom" : "2016-06-30"
        }
      ],

"ownersPeriod" : {
        "dateTo" : "",
        "dateFrom" : "2008-03-29"
      },

how to map or transform simple object to this type array

I map array using object mapper

public var ownersPeriodArray: [Model] = []

Here im using ObjectMapper library to convert json to my Model let model = Mapper().map(JSON: json)


Solution

  • You can try to run the code here if you want to quickly check it: http://online.swiftplayground.run/

    import Foundation
    
    let jsonObject = """
    {
        "ownersPeriod" : [
            {
              "dateTo" : "2013-06-17",
              "dateFrom" : "2012-09-15"
            },
            {
              "dateTo" : "2016-06-30",
              "dateFrom" : "2013-06-17"
            },
            {
              "dateTo" : "",
              "dateFrom" : "2016-06-30"
            }
          ]
    }
    """.data(using: .utf8)!
    
    let jsonArray = """
    {
        "ownersPeriod" : {
            "dateTo" : "",
            "dateFrom" : "2008-03-29"
          }
    }
    """.data(using: .utf8)!
    
    struct Owner: Codable {
        let ownersPeriod: CombinedType
    }
    
    struct OwnerPeriod: Codable {
        var dateTo: String
        var dateFrom: String
    }
    
    enum CombinedType: Codable {
        case array([OwnerPeriod])
        case object(OwnerPeriod)
    
        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            do {
                self = try .array(container.decode(Array.self))
            } catch DecodingError.typeMismatch {
                do {
                    self = try .object(container.decode(OwnerPeriod.self))
                } catch DecodingError.typeMismatch {
                    throw DecodingError.typeMismatch(CombinedType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Encoded type not expected"))
                }
            }
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            switch self {
            case .array(let array):
                try container.encode(array)
            case .object(let object):
                try container.encode(object)
            }
        }
    }
    
    let decoder = JSONDecoder()
    let object = try decoder.decode(Owner.self, from: jsonObject)
    let array = try decoder.decode(Owner.self, from: jsonArray)
    
    print(object)
    print(array)
    

    It prints:

    Owner(ownersPeriod: SwiftPlayground.CombinedType.array([SwiftPlayground.OwnerPeriod(dateTo: "2013-06-17", dateFrom: "2012-09-15"), SwiftPlayground.OwnerPeriod(dateTo: "2016-06-30", dateFrom: "2013-06-17"), SwiftPlayground.OwnerPeriod(dateTo: "", dateFrom: "2016-06-30")]))
    
    Owner(ownersPeriod: SwiftPlayground.CombinedType.object(SwiftPlayground.OwnerPeriod(dateTo: "", dateFrom: "2008-03-29")))