Как использовать декодируемый протокол со значениями пользовательских типов в Swift? - PullRequest
1 голос
/ 01 октября 2019

У меня есть 2 типа ответа в зависимости от моего запроса: Первый:

{
    "status": "success"
    "data": {
        "user_id": 2,
        "user_name": "John"      
    }
}

И второй:

{
    "status": "error",
    "data": [],
}

Я использую такую ​​структуру:

struct ValyutaListData:Decodable {
    let status: String? 
    let data: [String]?
}

Но если ответ является ответом первого типа, то произошла ошибка. Потому что в первом типе ответные данные не являются массивом. Это объект Json. Затем я использую такую ​​структуру:

struct ValyutaListData:Decodable {
    let status: String? 
    let data: Persondata?
}

struct Persondata: Decodable{
    let user_id: Int?
    let user_name: String?
}

Если ответ - ответ второго типа, ошибка будет иметь место. Какую структуру следует использовать для JSON динамического типа? Спасибо.

1 Ответ

1 голос
/ 02 октября 2019

Одним разумным решением является перечисление со связанным типом (ами)

struct User : Decodable {
    let userId: Int
    let userName: String
}

enum Result : Decodable {
    case success(User), failure

    enum CodingKeys: String, CodingKey { case status, data }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let status = try container.decode(String.self, forKey: .status)
        if status == "success" {
            let userData = try container.decode(User.self, forKey: .data)
            self = .success(userData)
        } else {
            self = .failure
        }
    }
}

И использовать его

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Result.self, from: data)
    switch result {
      case .success(let user): print(user)
      case .failure: print("An error occurred")
    }
} catch { print(error) }
...