Swift 可编码 - 如何获取 属性 位于层次结构中较高位置的结构的值?

Swift codable - how to get property value of struct located higher up in the hierarchy?

尝试重构一些遗留 JSON 解析代码以使用 Codable 并尝试重用现有的 Swift 结构,为简单起见,请考虑以下 JSON:

{
    "dateOfBirth":"2016-05-19"
      ...
    "discountOffer":[
        {
            "discountName":"Discount1"
            ...
        },
        {
            "discountName":"Discount2"
            ...
        }
    ]
}

在遗留代码中,Swift 结构折扣有一个 属性 'discountType',其值是根据从 JSON,问题是,如何将会员的出生日期传递给每个折扣结构?或者有没有办法让层次结构中较低的结构访问层次结构中较高的结构?

struct Member: Codable {
    var dateOfBirth: Date?
    var discounts: [Discount]?

}

struct Discount: Codable {
    var discountName: String?
    var memberDateOfBirth: Date? // *** Need to get it from Member but how?
    var discountType: String? // *** Will be determined by Member's dateOfBirth

    public init(from decoder: Decoder) throws {
        // self.memberDateOfBirth = // *** How to set from Member's dateOfBirth?????
        // use self.memberDateOfBirth to determine discountType
      ...
    }

}

我无法使用解码器的 userInfo 作为其获取 属性。我想过将 dateOfBirth 设置为某处的静态变量,但听起来很杂乱无章。

非常感谢任何帮助。谢谢

您可以像这样访问它们

init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.memberDateOfBirth = try values.decode(T.self, forKey: .result) //and whatever you want to do
        serverErrors = try values.decode([ServerError]?.self, forKey: .serverErrors)
    }

你可以这样试试:

let container = try decoder.container(keyedBy: CodingKeys.self)
let dateString = try container.decode(String.self, forKey: .memberDateOfBirth)
let formatter = "Your Date Formatter"
if let date = formatter.date(from: dateString) {
    memberDateOfBirth = date
}

如果您想了解更多信息,请查看此方法:

对于Dateformatter你可以检查:

您应该在 Member 中处理此问题,而不是 Discount,因为每个 Codable 类型都必须能够独立解码。

首先,将此添加到 Discount 以便仅对名称进行解码:

enum CodingKeys : CodingKey {
    case discountName
}

然后在Member实现自定义解码:

enum CodingKeys: CodingKey {
    case dateOfBirth, discounts
}

public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    dateOfBirth = try container.decode(Date.self, forKey: .dateOfBirth)
    discounts = try container.decode([Discount].self, forKey: .discounts)

    for i in 0..<discounts!.count {
        discounts![i].memberDateOfBirth = dateOfBirth
    }
}

末尾的 for 循环是我们为折扣赋值的地方。

回到 Discount,您可以使 discountType 成为一个依赖于 memberDateOfBirth 的计算 属性,或者添加一个 didSet 观察者到 memberDateOfBirth,你设置的地方 discountType.

var discountType: String? {
    if let dob = memberDateOfBirth {
        if dob < Date(timeIntervalSince1970: 0) {
            return "Type 1"
        }
    }
    return "Type 2"
}

// or

var memberDateOfBirth: Date? {
    didSet {
        if let dob = memberDateOfBirth {
            if dob < Date(timeIntervalSince1970: 0) {
                discountType = "Type 1"
            }
        }
        discountType = "Type 2"
    }
}