Swift codable - как получить значение свойства struct, расположенное выше в иерархии? - PullRequest
1 голос
/ 12 февраля 2020

Попытка рефакторинга некоего устаревшего JSON кода синтаксического анализа для использования Codable и попытка повторно использовать существующие структуры Swift, для простоты, пожалуйста, рассмотрите следующее JSON:

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

В устаревшем коде В Swift struct Discount есть свойство 'discountType', значение которого вычисляется на основе 'dateOfBirth' структуры члена, полученной из JSON. Вопрос в том, как передать dateOfBirth члена в каждую структуру Discount? Или есть способ для структур ниже в иерархии для доступа к структурам выше в иерархии?

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. Я думал о том, чтобы установить dateOfBirth как переменную stati c где-нибудь, но звучит как куча.

Буду признателен за любую помощь. Спасибо.

Ответы [ 3 ]

1 голос
/ 12 февраля 2020

Вы должны обрабатывать это в 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
    }
}

В конце для l oop мы даем значения скидкам.

Возвращаясь к 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"
    }
}
0 голосов
/ 12 февраля 2020

вы можете попробовать следующим образом:

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 вы можете проверить:

0 голосов
/ 12 февраля 2020

Вы можете получить к ним доступ вот так

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)
    }
...