Расшифровка Json не работает, также не дает ошибки - PullRequest
0 голосов
/ 04 апреля 2019

Я пытаюсь декодировать следующий json:

    [
        {
            "breeds":[
            {
            "weight":{
            "imperial":"65 - 75",
            "metric":"29 - 34"
            },
            "height":{
            "imperial":"21 - 28",
            "metric":"53 - 71"
            },
            "id":14,
            "name":"American Foxhound",
            "country_code":"US",
            "bred_for":"Fox hunting, scent hound",
            "breed_group":"Hound",
            "life_span":"8 - 15 years",
            "temperament":"Kind, Sweet-Tempered, Loyal, Independent, Intelligent, Loving"
            }
            ],
            "id":"p4xvDeEpW",
            "url":"https://cdn2.thedogapi.com/images/p4xvDeEpW.jpg",
            "width":680,
            "height":453
        }
    ]

Мои модели установлены как:

struct Request: Decodable {
    let response: [Response]
}

struct Response: Decodable {
    let breeds: [Dog]
    let url: String
}

struct Dog: Decodable {
    let weight: Measurement
    let height: Measurement
    let name: String
    let countryCode: String?
    let breedGroup: String
    let lifeSpan: String
    let temperament: String
    let origin: String?
}

struct Measurement: Decodable {
    let imperial: String
    let metric: String
}

Я вызываю API следующим образом:

func fetchDogs(with request: URLRequest, completion: @escaping (([Dog]?, String?, Error?) -> ())) {
    URLSession.shared.dataTask(with: request) { (data, response, error) in
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        guard let data = data,
            let request = try? decoder.decode(Request.self, from: data) else {
                completion(nil, nil, error)
                return
        }

        completion(request.response[0].breeds, request.response[0].url, nil)
        }.resume()
}

Но он всегда попадает в линию защиты completion(nil, nil, error), и я не уверен, почему я не уверен, как начать с нескольких первых строк JSON. Использование:

struct Request: Decodable {
    let response: [Response]
}

не кажется правильным. Если я обновлю запрос на декодирование структуры Response, он все равно попадет на защиту.

Мой конструктор запросов выглядит так:

struct RequestBuilder {
    private let baseURLString: String

    static var defaultBuilder: RequestBuilder {
        return RequestBuilder(
            baseURLString: Constant.URL.dogsBase
        )
    }

    func dogsRequest() -> URLRequest {
        return dogRequest(path: Constant.Path.search)
    }

    private func dogRequest(path: String) -> URLRequest {
        guard var components = URLComponents(string: baseURLString) else {
            preconditionFailure(Constant.PreconditionFailure.baseURL)
        }

        components.path = path

        guard let url = components.url else {
            preconditionFailure(Constant.PreconditionFailure.baseURL)
        }
        var request = URLRequest(url: url)
        request.setValue(Constant.Key.dogs, forHTTPHeaderField: "x-api-key")

        return request
    }
}

API можно найти здесь

1 Ответ

2 голосов
/ 04 апреля 2019

Проблема в том, что когда вы передаете Request.self в decode.decode, JSONDecoder ожидает найти Dictionary с ключом response из-за вашего объявления Request.

Вам просто нужно передать [Response].self методу decode.

guard let data = data,
    let request = try? decoder.decode([Response].self, from: data) else {
        completion(nil, nil, error)
        return
}

Если вы не маскируете ошибку декодирования с помощью try?, вы сразу увидите сообщение об ошибке:

typeMismatch (Swift.Dictionary, Swift.DecodingError.Context (codingPath: [], debugDescription: «Ожидается декодирование словаря, но вместо него найден массив.», UnderError: nil))

Вы всегда должны использовать обычный оператор try в блоке do-catch, когда вы не уверены, будет ли ваш код работать или нет, так как таким образом вы можете увидеть сообщение об ошибке. JSONDecoder выдает довольно полезные ошибки, поэтому я бы посоветовал вам никогда не маскировать их в nil, используя try?.

...