简体   繁体   中英

How to parse JSON to nested struct in Swift?

I'm going to parse this JSON:

{
    "status": 1,
    "member": {
        "id": "3",
        "member_no": "1111",
        "username": "uname",
        "name": "name",
        "email": "user@name.com",
        "phone": "123 123",
        "point": "100",
        "expiry": "2019-09-22",
        "grade": {
            "id": "2",
            "name": "Member"
        }
    }
}

I created this struct:

struct User: Codable {
    var status: Int?
    var member: Member?
    var msg: String?

    struct Member: Codable {
        var id: Int?
        var member_no: String?
        var username: String?
        var name: String?
        var email: String?
        var phone: String?
        var point: String?
        var expiry: String?
        var grade: Grade?

        struct Grade: Codable {
            var id: Int?
            var name: String?
        }
    }
}

And use this to decode:

let decoder = JSONDecoder()
let user = try decoder.decode(User.self, from: data)

But I got this error:

The data couldn't be read because it isn't in the correct format.

If the struct only one level, it is no problem:

struct User: Codable {
    var status: Int?
    var msg: String?
}

How to write a struct to match this JSON?

You might want to try as following, which seems to work fine for me.

First we need to create CodingKeys for our struct User

When working with codable, even though Member and Grade inside of member are nested each other. You should declare those structs, out of the User struct.

As you can see on the following Member and Grade should conform to Codable , while User conforms to Decodable in an extension and initializes with a decoder by using it as a container.

Also since in your json file you have id as String in both User and Grade but in your code you declared them as Int so I have also fixed them.

The code below implements structs and CodingKeys as I have mentioned above, try to approach as I did or try it by copying pasting it, and it should be fine:

User struct with CodingKeys:

struct User {
var status: Int?
var member: Member?

enum CodingKeys: String, CodingKey {
    case status = "status"
    case member = "member"
}
}

Member and Grade structs:

struct Member: Codable {
var id: String?
var member_no: String?
var username: String?
var name: String?
var email: String?
var phone: String?
var point: String?
var expiry: String?
var grade: Grade?
}

struct Grade: Codable {
var id: String?
var name: String?
}

Extension for User to conform Codable:

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

    self.status = try container.decode(Int?.self, forKey: .status)
    self.member = try container.decode(Member?.self, forKey: .member)
}
}

Now create a decoder and try to decode it as following:

    let decoder = JSONDecoder()
    let user = try! decoder.decode(User.self, from: data)

I hope this helps and work fine for you

xcode has probably thrown you an error, saying your struct doesn't conform to the decodable protocol, you didn't care about it :]

here is what your struct (model) should look like


struct User: Codable {
    let status: Int?
    let member: Member?
}

struct Member: Codable { let id, memberNo, username, name: String? let email, phone, point, expiry: String? let grade: Grade?

enum CodingKeys: String, CodingKey {
    case id
    case memberNo = "member_no"
    case username, name, email, phone, point, expiry, grade
}

}

struct Grade: Codable { let id, name: String? }

Try this

import Foundation

struct User: Codable {
    let status: Int
    let member: Member
}

struct Member: Codable {
    let id, memberNo, username, name: String
    let email, phone, point, expiry: String
    let grade: Grade

    enum CodingKeys: String, CodingKey {
        case id
        case memberNo = "member_no"
        case username, name, email, phone, point, expiry, grade
    }
}

struct Grade: Codable {
    let id, name: String
}

struct User: Codable { var status: Int? var member: Member? var msg: String?

struct Member: Codable {
    var id: String?
    var member_no: String?
    var username: String?
    var name: String?
    var email: String?
    var phone: String?
    var point: String?
    var expiry: String?
    var grade: Grade?

    struct Grade: Codable {
        var id: String?
        var name: String?
    }
}

}

You have strings in the ids and not integers:

struct User: Codable {
    var status: Int?
    var member: Member?

    struct Member: Codable {
        var id: String?
        var member_no: String?
        var username: String?
        var name: String?
        var email: String?
        var phone: String?
        var point: String?
        var expiry: String?
        var grade: Grade?

        struct Grade: Codable {
            var id: String?
            var name: String?
        }
    }
}

let decoder = JSONDecoder()
do {
    let user = try decoder.decode(User.self, from: data)
} catch {
    print(error)
}

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