Как подготовить ответ API для использования с jsonDecoder в Swift - PullRequest
0 голосов
/ 02 февраля 2019

когда я вызываю API и получаю ответ от сервера с Alamofire, я хочу использовать объект «data» из json

, эти данные поступают из API

{
    "code": 200,
    "hasError": false,
    "data": [
        {
            "userSession": "43a1bd70-26bf-11e9-9ccd-00163eaf6bb4"
        }
    ],
    "message": "ok"
}

, и мне нужна карта data к моему AuthModel

это мой AuthModel:

struct AuthModel: Codable {
    let userSession: String

    enum CodingKeys: String, CodingKey {
        case userSession = "userSession"
    }
}

я закодировал эти строки, но это не работает:

if let responseObject = response.result.value as? Dictionary<String,Any> {
    if let hasError = responseObject["hasError"] as? Bool {
        guard !hasError else { return }
        do {
            let decoder = JSONDecoder()
            let authModel = try decoder.decode(AuthModel.self, from: responseObject["data"])
        } catch {
            print("Parse Error: ",error)
        }
    }
}

это делаетне работает, потому что responseObject["data"] не является NSData Type

Невозможно преобразовать значение типа '[String: Any]' в ожидаемый тип аргумента 'Data'

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Я думаю, что ваш ответ API является шаблоном, который указывает:

  • Есть ли у нас какие-либо проблемы (ошибки)?
  • Есть ли у нас ожидаемые данные?

Исходя из этого, мы можем использовать Enum и Generics.Например:

class ResponseObject<T: Codable>: Codable {

    private var code        : Int
    private var hasError    : Bool
    private var message     : String
    private var data        : T?

    var result: Result {
        guard !hasError else { return .error(code, message) }
        guard let data = data else { return .error(0, "Data is not ready.") }
        return .value(data)
    }

    enum Result {
        case error(Int, String)
        case value(T)
    }

}

и мы можем использовать ResponseObject с нашим ожидаемым data:

let responseString = """
{
    "code": 200,
    "hasError": false,
    "data": [
        {
            "userSession": "43a1bd70-26bf-11e9-9ccd-00163eaf6bb4"
        }
    ],
    "message": "ok"
}
"""

class AuthObject: Codable {
    var userSession : String

}

if let jsonData = responseString.data(using: .utf8) {
    do {
        //ResponseObject<[AuthObject]> means: if we don't have error, the `data` object in response, will represent `[AuthObject]`.
        let responseObject = try JSONDecoder().decode(ResponseObject<[AuthObject]>.self, from: jsonData)

        //Using ResponseObject.Result Enum: We have error with related code and message, OR, we have our expected data.
        switch responseObject.result {
        case .error(let code, let message):
            print("Error: \(code) - \(message)")
        case .value(let authObjects):
            print(authObjects.first!.userSession)
        }

    } catch {
        print(error.localizedDescription)
    }
}
0 голосов
/ 02 февраля 2019

Получите ответ Data вместо десериализованного Dictionary например

Alamofire.request(url).responseData { response in

и декодируйте

let decoder = JSONDecoder()
let authModel = try decoder.decode(AuthModel.self, from: response.data!)

в эти структуры

struct AuthModel : Decodable {
    let code : Int
    let hasError : Bool
    let message : String
    let data : [Session]
}

struct Session : Decodable {
    let userSession: String
}

Все ключи кодирования синтезированы.

...