繁体   English   中英

Swift 可解码:如何在解码过程中转换其中一个值?

[英]Swift Decodable: how to transform one of values during decoding?

默认情况下, Decodable协议将 JSON 值转换为 object 值,没有任何变化。 但有时您需要在 json 解码期间转换值,例如,在 JSON 中您得到{id = "id10"}但在您的 class 实例中您需要将数字10放入属性id (或什至具有不同名称的属性)。

您可以实现方法init(from:) ,您可以在其中使用任何值执行您想要的操作,例如:

public required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    latitude = try container.decode(Double.self, forKey:.latitude)
    longitude = try container.decode(Double.self, forKey: .longitude)
    // and for example there i can transform string "id10" to number 10
    // and put it into desired field
}

这对我来说听起来不错,但如果我只想更改 JSON 字段之一的值,而让其他 20 个字段保持不变怎么办? init(from:)的情况下,我应该为我班级的 20 个字段中的每一个字段手动获取和放置值! 经过多年的 objC 编码,我很直观地首先调用 super 的init(from:)实现,然后仅对某些字段进行更改,但我如何使用 Swift 和Decodable协议实现这样的效果?

你可以使用lazy var 缺点是你仍然需要提供一个键列表,你不能声明你的模型是一个常量:

struct MyModel: Decodable {
    lazy var id: Int = {
        return Int(_id.replacingOccurrences(of: "id", with: ""))!
    }()
    private var _id: String

    var latitude: CGFloat
    var longitude: CGFloat

    enum CodingKeys: String, CodingKey {
        case latitude, longitude
        case _id = "id"
    }
}

例:

let json = """
{
    "id": "id10",
    "latitude": 1,
    "longitude": 1
}
""".data(using: .utf8)!

// Can't use a `let` here
var m = try JSONDecoder().decode(MyModel.self, from: json)
print(m.id)

当前,如果您想要更改甚至单个属性的解析,则必须完全实现encodedecode方法。

Swift Codable 的某些未来版本可能会允许逐个处理每个属性的编码和解码。 但是 Swift 功能工作非常重要,尚未确定优先级:

无论如何,我们的目标是可能提供一种强类型的解决方案,允许您根据具体情况执行此操作,而不会掉下“悬崖”而不得不实施所有encode(to:init(from:为了一个财产的利益;解决方案可能很重要,需要大量 API 讨论才能弄清楚如何做好,因此我们还不能做到这一点。

- Itai Ferber,Swift 4 Codable 的首席开发人员

https://bugs.swift.org/browse/SR-5249?focusedCommentId=32638

暂无
暂无

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

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