尝试重构一些遗留的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,因为它是一个 get 属性。我想在某处将出生日期设置为静态变量,但听起来像是笨拙的。
将不胜感激任何帮助。 谢谢。
你应该用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"
}
}
您可以像这样访问它们
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
}
如果您想了解更多信息,请查看此方法:
- https://useyourloaf.com/blog/swift-codable-with-custom-dates/
对于Dateformatter
,您可以查看:
- Swift 中的日期格式
- https://nsdateformatter.com