Насколько я вижу в вашем случае, SaleToPOIRequest
содержит свойство типа PaymentRequestStr
или LoginRequestStr
.Я бы порекомендовал вам объявить enum
со связанными значениями для хранения экземпляра PaymentRequestStr
или LoginRequestStr
.Проверьте этот фрагмент кода:
enum LoginOrPaymentRequest: Decodable {
case login(LoginRequestStr)
case payment(PaymentRequestStr)
case unknown
private enum CodingKeys: String, CodingKey {
case LoginRequest
case PaymentRequest
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let loginRequest = try container.decodeIfPresent(LoginRequestStr.self, forKey: .LoginRequest) {
self = .login(loginRequest)
} else if let paymentRequest = try container.decodeIfPresent(PaymentRequestStr.self, forKey: .PaymentRequest) {
self = .payment(paymentRequest)
} else {
self = .unknown
}
}
}
Также измените реализацию SaleToPOIRequest
, добавьте свойство типа LoginOrPaymentRequest
:
struct SaleToPOIRequest: Decodable {
let messageHeader: MessageHeaderStr?
let loginOrPaymentRequest: LoginOrPaymentRequest
private enum CodingKeys: String, CodingKey {
case MessageHeader
}
private init(messageHeader: MessageHeaderStr?,
loginOrPaymentRequest: LoginOrPaymentRequest) {
self.messageHeader = messageHeader
self.loginOrPaymentRequest = loginOrPaymentRequest
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.init(messageHeader: try container.decode(MessageHeaderStr.self, forKey: .MessageHeader),
loginOrPaymentRequest: try LoginOrPaymentRequest(from: decoder))
}
}
Эта структура содержит информацию об экземпляреSaleToPOIRequest
:
struct DataResponse: Decodable {
let saleToPOIRequest: SaleToPOIRequest?
private enum CodingKeys: String, CodingKey {
case SaleToPOIRequest
}
private init(saleToPOIRequest: SaleToPOIRequest?) {
self.saleToPOIRequest = saleToPOIRequest
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.init(saleToPOIRequest: try container.decode(SaleToPOIRequest.self, forKey: .SaleToPOIRequest))
}
}
Как это проверить:
let dataResponse = try JSONDecoder().decode(DataResponse.self, from: json)
print(dataResponse.saleToPOIRequest?.messageHeader?.POIID)
if let loginOrPaymentRequest = dataResponse.saleToPOIRequest?.loginOrPaymentRequest {
if case .login(let loginRequest) = loginOrPaymentRequest {
print(loginRequest.OperatorLanguage)
} else if case .payment(let paymentRequest) = loginOrPaymentRequest {
print(paymentRequest.PaymentData.PaymentType)
}
}
Я помню, что вы упомянули, что вам нужно проверить значение MessageCategory
.В таком случае добавьте эту функцию к LoginOrPaymentRequest
:
init(from decoder: Decoder, messageCategory: String) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let loginRequest = try container.decodeIfPresent(LoginRequestStr.self, forKey: .LoginRequest), messageCategory == "Login" {
self = .login(loginRequest)
} else if let paymentRequest = try container.decodeIfPresent(PaymentRequestStr.self, forKey: .PaymentRequest), messageCategory == "Payment" {
self = .payment(paymentRequest)
} else {
self = .unknown
}
}
и измените init
из SaleToPOIRequest
:
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let messageHeader = try container.decode(MessageHeaderStr.self, forKey: .MessageHeader)
let loginOrPaymentRequest = try LoginOrPaymentRequest(from: decoder,
messageCategory: messageHeader.MessageCategory)
self.init(messageHeader: messageHeader,
loginOrPaymentRequest: loginOrPaymentRequest)
}