简体   繁体   English

Swift Json 解码嵌套数组/字典到平面 model

[英]Swift Json decoding nested array / dictionary to flat model

I am trying to decode the following json object to my User model in Swift.我正在尝试将以下 json object 解码给我在 Swift 中的User model。

My issue is decoding the values _id and token out of the tokens array, where the first token in the array contains the values I want to decode into User.tokenId and User.token.我的问题是从tokens数组中解码值_idtoken ,其中数组中的第一个令牌包含我要解码为 User.tokenId 和 User.token 的值。

I am trying to extract/map the values directly into my User model struct without having another nested struct in my User model ( such as struct Token { var id: String, var token: String } )我正在尝试将值直接提取/映射到我的用户 model 结构中,而我的用户 model 中没有另一个嵌套结构(例如struct Token { var id: String, var token: String }

let json = """
    {
        "currentLocation": {
            "latitude": 0,
            "longitude": 0
        },
        "profileImageUrl": "",
        "bio": "",
        "_id": "601453e4aae564fc19075b68",
        "username": "johnsmith",
        "name": "john",
        "email": "johnsmith@gmail.com",
        "keywords": ["word", "weds"],
        "tokens": [
            {
                "_id": "213453e4aae564fcqu775b69",
                "token": "eyJhbGciOiJIUzqoNiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MDE0NTNlNGFhZTU2NGZjMTkwNzViNjgiLCJpYXQiOjE2MTE5NDQ5MzIsImV4cCI6MTYxMjM3NjkzMn0.PbTsA3B0MAfcVvEF1UAMhUXFiqIL1FcxVFGgMTZ5HCk"
            }
        ],
        "createdAt": "2021-01-29T18:28:52.845Z",
        "updatedAt": "2021-01-29T18:28:52.883Z"
    }
    """.data(using: .utf8)!


struct User: Codable {
    var latitude: Double 
    var longitude: Double 
    var profileImageUrl: String 
    var bio: String 
    var userId: String 
    var username: String
    var name: String
    var email: String
    var keywords: [String]
    var tokenId: String
    var token: String
    var createdAt: Date
    var updatedAt: Date
    
    private enum UserKeys: String, CodingKey {
        case currentLocation
        case profileImageUrl
        case bio
        case userId = "_id"
        case username
        case name
        case email
        case keywords
        case tokens
        case createdAt
        case updatedAt
    }
    
    private enum CurrentLocationKeys: String, CodingKey { 
        case latitude
        case longitude
    }
    
    private enum TokenKeys: String, CodingKey {
        case tokenId = "_id"
        case token
    }
    
    init(from decoder: Decoder) throws {
        
        let userContainer = try decoder.container(keyedBy: UserKeys.self)
              let currentLocationContainer = try userContainer.nestedContainer(keyedBy: CurrentLocationKeys.self, forKey: .currentLocation) 
              self.latitude = try currentLocationContainer.decode(Double.self, forKey: .latitude)
              self.longitude = try currentLocationContainer.decode(Double.self, forKey: .longitude)
            self.profileImageUrl = try userContainer.decode(String.self, forKey: .profileImageUrl)
            self.bio = try userContainer.decode(String.self, forKey: .bio)
            self.userId = try userContainer.decode(String.self, forKey: .userId)
            self.username = try userContainer.decode(String.self, forKey: .username)
            self.name = try userContainer.decode(String.self, forKey: .name)
            self.email = try userContainer.decode(String.self, forKey: .email)
            self.keywords = try userContainer.decode([String].self, forKey: .keywords)
              let tokensContainer = try userContainer.nestedContainer(keyedBy: TokenKeys.self, forKey: .tokens)
              self.tokenId = try tokensContainer.decode(String.self, forKey: .tokenId)
              self.token = try tokensContainer.decode(String.self, forKey: .token)
            self.createdAt = try userContainer.decode(Date.self, forKey: .createdAt)
            self.updatedAt = try userContainer.decode(Date.self, forKey: .updatedAt)
    }
}

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

First of all I assume that your decoder has an appropriate date decoding strategy to be able to decode the ISO8601 strings to Date .首先,我假设您的decoder具有适当的日期解码策略,能够将 ISO8601 字符串解码为Date

The enclosing container of the token dictionary is an array. token字典的封闭容器是一个数组。 You have to insert an intermediate nestedUnkeyedContainer您必须插入一个中间nestedUnkeyedContainer

...
var arrayContainer = try userContainer.nestedUnkeyedContainer(forKey: .tokens)
let tokensContainer = try arrayContainer.nestedContainer(keyedBy: TokenKeys.self)
self.tokenId = try tokensContainer.decode(String.self, forKey: .tokenId)
self.token = try tokensContainer.decode(String.self, forKey: .token)
...

It's much less code to decode the JSON into multiple structs将 JSON 解码为多个结构的代码要少得多

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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