Не удается декодировать JSON, потому что пропущен Content-Type - PullRequest
0 голосов
/ 02 февраля 2019

Мой JSONDecoder (). Decode не может декодировать данные в формат json, потому что у ответа сервера есть Content-Type, подобный этому "* \ *; charset = utf8".

Что мне нужно сделать в этомситуация?Есть идеи? Ссылка API

Мой код:

private static let livePhotoUrlString = "https://m1.kappboom.com/livewallpapers/info?o=0&v=575"

static func getLivePhotos(completionHandler: @escaping (([LivePhoto]) -> Void)) {
    guard let livePhotoUrl = URL(string: livePhotoUrlString) else { return }
    let semaphore = DispatchSemaphore(value: 0)

    URLSession.shared.dataTask(with: livePhotoUrl) { (data, response, error) in
         do {
             guard let data = data else { return }
             let livePhotos = try JSONDecoder().decode([LivePhoto].self, from: data)
             completionHandler(livePhotos)
         } catch {
             completionHandler([])
         }
         semaphore.signal()
     }.resume()
     semaphore.wait()
}

Моя сущность (LivePhoto):

class LivePhoto: Decodable {

    init(smallUrl: String, largeUrl: String, movieUrl: String, id: Int, isLocked: Bool, promotionalUnlock: Bool) {
        self.smallUrl = smallUrl
        self.largeUrl = largeUrl
        self.movieUrl = movieUrl
        self.id = id
        self.isLocked = isLocked
        self.promotionalUnlock = promotionalUnlock
    }

    var smallUrl: String
    var largeUrl: String
    var movieUrl: String
    var id: Int
    var isLocked: Bool
    var promotionalUnlock: Bool
}

Заголовки ответа:

response headers

Правильный ответ (другой API):

correct response

Ответы [ 3 ]

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

Вы уверены, что это проблема, мне кажется, вам нужно определить ключи кодирования для вашей структуры

enum CodingKeys: String, CodingKey {
    case smallUrl = "small_url"
    case largeUrl = "large_url"
    case movieUrl = "movie_url"
    case isLocked = "is_locked"
    case promotionalUnlock = "promotional_unlock"
    case id
}
0 голосов
/ 02 февраля 2019

Ошибка не связана с типом содержимого.

Вместо того, чтобы игнорировать ошибку в catch блоке print it, ошибки декодирования очень описательны.

} catch {
    print(error)
    completionHandler([])
}

В нем указывается

keyNotFound (CodingKeys (stringValue: "smallUrl", intValue: nil), Swift.DecodingError.Context (codingPath: [_JSONKey (stringValue: "Index 0", intValue:0)], debugDescription: "Нет значения, связанного с ключом CodingKeys (stringValue: \" smallUrl \ ", intValue: nil) (\" smallUrl \ ").", UnderError: nil))

Вы сразу видите, что ключ small_url, а ваш член структуры - smallUrl.

Самое простое решение - добавить стратегию декодирования ключа convertFromSnakeCase

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let livePhotos = try decoder.decode([LivePhoto].self, from: data)

И выне нужен метод init в классе.Объявите это как структуру с постоянными членами

struct LivePhoto: Decodable {
    let smallUrl, largeUrl, movieUrl: String
    let id: Int
    let isLocked: Bool
    let promotionalUnlock: Bool
}

И, пожалуйста, удалите это ужасное semaphore.Так как вы все равно используете обработчик завершения, это бессмысленно.

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

Вам нужно использовать имена ключей, как они есть в json, или написать перечисление с преобразованными именами, но лучше использовать convertFromSnakeCase

  func getLivePhotos(completionHandler: @escaping (([LivePhoto]) -> Void)) {
        guard let livePhotoUrl = URL(string: livePhotoUrlString) else { return }

        URLSession.shared.dataTask(with: livePhotoUrl) { (data, response, error) in
              print(data)
            do {
                guard let data = data else { return }
                let dec = JSONDecoder()
                dec.keyDecodingStrategy = .convertFromSnakeCase
                let livePhotos = try dec.decode([LivePhoto].self, from: data)
                completionHandler(livePhotos)
            } catch {
                print(error)
                completionHandler([])
            }

            }.resume()

    }



}

struct LivePhoto: Codable {
    let id: Int
    let smallUrl, largeUrl: String
    let movieUrl: String
    let isLocked, promotionalUnlock: Bool

}

Также это лучшийСтарайтесь всегда print(error) внутри блока catch, чтобы вы могли знать об ошибке и исправить ее, здесь нет места для семафоров, это только работа завершения, также вы можете показывать индикатор активности, пока запрос не завершится каклучший UX

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...