代码之家  ›  专栏  ›  技术社区  ›  Charlie Fish

Swift可解码可选钥匙

  •  20
  • Charlie Fish  · 技术社区  · 7 年前

    (这是这个问题的后续: Using Decodable protocol with multiples keys .)

    我有以下Swift代码:

    let additionalInfo = try values.nestedContainer(keyedBy: UserInfoKeys.self, forKey: .age)
    age = try additionalInfo.decodeIfPresent(Int.self, forKey: .realage)
    

    我知道如果我使用 decodeIfPresent 如果它是可选变量,那么它仍然可以正确处理它。

    例如,下面的JSON使用上面的代码对其进行解析。

    {
        "firstname": "Test",
        "lastname": "User",
        "age": {"realage": 29}
    }
    

    下面的JSON也可以工作。

    {
        "firstname": "Test",
        "lastname": "User",
        "age": {"notrealage": 30}
    }
    

    但以下方法不起作用。

    {
        "firstname": "Test",
        "lastname": "User"
    }
    

    我怎样才能让这三个例子都起作用?有类似的吗 解码当前 对于 nestedContainer ?

    3 回复  |  直到 7 年前
        1
  •  60
  •   Paulo Mattos    6 年前

    KeyedDecodingContainer 功能:

    func contains(_ key: KeyedDecodingContainer.Key) -> Bool
    

    返回a Bool 指示解码器是否包含与给定键相关联的值的值。与给定键相关联的值可以是适用于数据格式的空值。

    "age" 密钥存在 之前 请求相应的嵌套容器:

    struct Person: Decodable {
        let firstName, lastName: String
        let age: Int?
    
        enum CodingKeys: String, CodingKey {
            case firstName = "firstname"
            case lastName = "lastname"
            case age
        }
    
        enum AgeKeys: String, CodingKey {
            case realAge = "realage"
            case fakeAge = "fakeage"
        }
    
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            self.firstName = try values.decode(String.self, forKey: .firstName)
            self.lastName = try values.decode(String.self, forKey: .lastName)
    
            if values.contains(.age) {
                let age = try values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
                self.age = try age.decodeIfPresent(Int.self, forKey: .realAge)
            } else {
                self.age = nil
            }
        }
    }
    
        2
  •  13
  •   TomCobo    5 年前

    我有这个问题,我找到了这个解决方案,以防万一对其他人有帮助:

    let ageContainer = try? values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
    self.age = try ageContainer?.decodeIfPresent(Int.self, forKey: .realAge)
    

    如果有可选容器,请使用 try? values.nestedContainer(keyedBy:forKey) 您不需要使用检查容器是否存在 contains( .

        3
  •  3
  •   David Siegel    7 年前

    你能试着把你的示例JSON粘贴到 quicktype 看看它能推断出什么类型?基于您的问题,我粘贴了您的样品并获得:

    struct UserInfo: Codable {
        let firstname: String
        let age: Age?
        let lastname: String
    }
    
    struct Age: Codable {
        let realage: Int?
    }
    

    制作 UserInfo.age Age.realage