简体   繁体   中英

Swift Json decoding with unsure incoming data

I'm struggeling to decode some Json data in swift.

My back-end api will return me either an array of X or an object with (at least) one property named "items" of type array of X.

I've searched but found no solutions. Do you have any?

struct A: Decodable {
   var items: [X]
   // some other optional properties

   public init(from decoder: Decoder) throws {
       // Sometimes I receive the correct A object
       // Sometimes I only receive the array of X without the surrounding object of type A.
   }
}

And to make things worst, I'm bound to decode like I was always receiving an object of typa A... :

myObjectOfTypeA = try decoder.decode(A.self, from: data)

Most of the time, I'll receive a proper A object like this:

{
    "items": 
    [
        {
            "id": 7,
            "startsOn": "2021-03-01",
            "endsOn": "2021-12-31"
        },
        {
            "id": 6,
            "startsOn": "2021-04-19",
            "endsOn": "2022-04-04"
        }
    ],
    "next": null,
    "prev": null,
    "count": 2
}

But sometimes, I'll receive only the items array like this:

[
    {
        "id": 7,
        "startsOn": "2021-03-01",
        "endsOn": "2021-12-31"
    },
    {
        "id": 6,
        "startsOn": "2021-04-19",
        "endsOn": "2022-04-04"
    }
]

Any ideas would be greatly appreciated because I'm clearly out of ideas myself...

You just need to try to decode your enclosing type items and catch the error. If it is a type mismatch error try to decode it again. No need to create a custom decoder:


struct A: Decodable {
   let items: [X]
}

struct X: Decodable {
    let id: Int
    let startsOn: Date
    let endsOn: Date
}

Playground testing:

let json = """
{
    "items":
    [
        {
            "id": 7,
            "startsOn": "2021-03-01",
            "endsOn": "2021-12-31"
        },
        {
            "id": 6,
            "startsOn": "2021-04-19",
            "endsOn": "2022-04-04"
        }
    ],
    "next": null,
    "prev": null,
    "count": 2
}
"""

let dateFormatter = DateFormatter()
dateFormatter.calendar = .init(identifier: .iso8601)
dateFormatter.locale = .init(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd"

let jsonDecoder = JSONDecoder()
jsonDecoder.dateDecodingStrategy = .formatted(dateFormatter)
let items: [X]
do {
    items = try jsonDecoder.decode(A.self, from: Data(json.utf8)).items
} catch DecodingError.typeMismatch {
    items = try jsonDecoder.decode([X].self, from: Data(json.utf8))
} catch {
    items = []
    print(error)
}
print(items)

It will print the following for both json inputs:

[X(id: 7, startsOn: 2021-03-01 03:00:00 +0000, endsOn: 2021-12-31 03:00:00 +0000), X(id: 6, startsOn: 2021-04-19 03:00:00 +0000, endsOn: 2022-04-04 03:00:00 +0000)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM