使用 Codable 解码具有相似键的嵌套 JSON
Decode nested JSON with similar keys using Codable
我正在尝试解码嵌套 JSON。问题是顶级和嵌套键的名称相似。喜欢:
{
success: bool
message: String
error: {
message: String
}
}
我会从后端收到成功消息或失败消息。如果成功为真,则不会返回错误密钥,如果为假,则将错误与消息一起发送。
所以如果成功了:
{
success: true
message: "Success message"
}
如果失败:
{
success: false
error:{
message: "Failed message"
}
}
以上就是返回的json。这是我的解码结构:
struct loginResponse : Codable{
var success: Bool
var success_message: String
var error_message: String
enum loginResponseKeys: String, CodingKey{
case success
case error
case success_message = "message" // raw value is not unique
case error_message = "message"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: loginResponseKeys.self)
let error = try container.nestedContainer(keyedBy: loginResponseKeys.self, forKey: .error)
error_message = try error.decode(String.self, forKey: .error_message)
let message = try container.decode(String.self, forKey:.success_message)
}
没错,它说原始值不是唯一的。但是我该如何克服呢?
您只需要创建一个嵌套的 ErrorResponse
结构。将 message
和 error
设为可选,并根据 success
.
的值仅解码其中之一
您还应遵守 Swift 命名约定,即类型名称为 UpperCamelCase,变量名称为 lowerCamelCase。
struct LoginResponse : Codable{
let success: Bool
var successMessage: String?
var error: ErrorResponse?
struct ErrorResponse: Codable {
let message: String
}
enum LoginResponseKeys: String, CodingKey{
case success, error, successMessage = "message"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: LoginResponseKeys.self)
success = try container.decode(Bool.self, forKey: .success)
if success {
successMessage = try container.decode(String.self, forKey: .successMessage)
} else {
error = try container.decode(ErrorResponse.self, forKey: .error)
}
}
}
您可以为 ErrorMessage 创建结构
struct LoginResponse: Codable {
let success: Bool
let message: String?
let error: ErrorMessage?
}
struct ErrorMessage: Codable {
let message: String?
}
extension LoginResponse {
init(data: Data) throws {
self = try JSONDecoder().decode(LoginResponse.self, from: data)
}
}
假设这个 Json:
{
"success": true,
"message": "success",
"error": {
"message": "Error Message"
}
}
可能会使用 KeyedCodable,请注意您将有单个 "message" 属性,其中包含成功或失败的消息,具体取决于 "success" 值:
struct LoginResponse: Codable, Keyedable {
private(set) var success: Bool!
private(set) var message: String!
mutating func map(map: KeyMap) throws {
try success <-> map["success"]
let messageKey = success ? "message" : "error.message"
try message <-> map[messageKey]
}
init(from decoder: Decoder) throws {
try KeyedDecoder(with: decoder).decode(to: &self)
}
}
我正在尝试解码嵌套 JSON。问题是顶级和嵌套键的名称相似。喜欢:
{
success: bool
message: String
error: {
message: String
}
}
我会从后端收到成功消息或失败消息。如果成功为真,则不会返回错误密钥,如果为假,则将错误与消息一起发送。
所以如果成功了:
{
success: true
message: "Success message"
}
如果失败:
{
success: false
error:{
message: "Failed message"
}
}
以上就是返回的json。这是我的解码结构:
struct loginResponse : Codable{
var success: Bool
var success_message: String
var error_message: String
enum loginResponseKeys: String, CodingKey{
case success
case error
case success_message = "message" // raw value is not unique
case error_message = "message"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: loginResponseKeys.self)
let error = try container.nestedContainer(keyedBy: loginResponseKeys.self, forKey: .error)
error_message = try error.decode(String.self, forKey: .error_message)
let message = try container.decode(String.self, forKey:.success_message)
}
没错,它说原始值不是唯一的。但是我该如何克服呢?
您只需要创建一个嵌套的 ErrorResponse
结构。将 message
和 error
设为可选,并根据 success
.
您还应遵守 Swift 命名约定,即类型名称为 UpperCamelCase,变量名称为 lowerCamelCase。
struct LoginResponse : Codable{
let success: Bool
var successMessage: String?
var error: ErrorResponse?
struct ErrorResponse: Codable {
let message: String
}
enum LoginResponseKeys: String, CodingKey{
case success, error, successMessage = "message"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: LoginResponseKeys.self)
success = try container.decode(Bool.self, forKey: .success)
if success {
successMessage = try container.decode(String.self, forKey: .successMessage)
} else {
error = try container.decode(ErrorResponse.self, forKey: .error)
}
}
}
您可以为 ErrorMessage 创建结构
struct LoginResponse: Codable {
let success: Bool
let message: String?
let error: ErrorMessage?
}
struct ErrorMessage: Codable {
let message: String?
}
extension LoginResponse {
init(data: Data) throws {
self = try JSONDecoder().decode(LoginResponse.self, from: data)
}
}
假设这个 Json:
{
"success": true,
"message": "success",
"error": {
"message": "Error Message"
}
}
可能会使用 KeyedCodable,请注意您将有单个 "message" 属性,其中包含成功或失败的消息,具体取决于 "success" 值:
struct LoginResponse: Codable, Keyedable {
private(set) var success: Bool!
private(set) var message: String!
mutating func map(map: KeyMap) throws {
try success <-> map["success"]
let messageKey = success ? "message" : "error.message"
try message <-> map[messageKey]
}
init(from decoder: Decoder) throws {
try KeyedDecoder(with: decoder).decode(to: &self)
}
}