Расшифруйте вложенный JSON с похожими ключами, используя Codable - PullRequest
0 голосов
/ 31 мая 2018

Я пытаюсь декодировать вложенный JSON.Проблема в том, что имена верхнего уровня и вложенных ключей похожи.Как:

{
    success: bool
     message: String
     error: {
      message: String
         }
} 

С серверной части я получаю сообщение об успехе или сообщение об ошибке.Если успех равен true, ключ ошибки не будет возвращен обратно, а если он равен false, то сообщение об ошибке вместе с сообщением отправляется.

, поэтому, если он успешен:

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

Правильно, это говорит о том, что необработанное значение не является уникальным.Но как мне преодолеть это?

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

вы можете создать структуру для 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"
         }
} 
0 голосов
/ 31 мая 2018

Используя 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)
    }
}
0 голосов
/ 31 мая 2018

Вам просто нужно создать вложенную 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)
        }
    }
}
...