Декодировать массив JSON с использованием обобщений и Decodable - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь создать приложение, чтобы научиться использовать дженерики в Swift.Поэтому я решил использовать API Studio Ghibli

. Для этого я делаю следующее:

  1. Создайте запрос к API
  2. Получитьответ
  3. Разбор JSON

Как и в их API, вся информация поставляется с baseURL, равным https://ghibliapi.herokuapp.com, и все конечные точки baseURL/foo и возвращаютмассив любой информации, которую мы хотим.Итак, для этого конкретного случая я пытаюсь использовать /films и /people.

Так что, в моей голове, было бы лучше иметь универсальную функцию декодирования, которая делает это и возвращает массивсоответствующего класса, который мы хотим декодировать.

private func decode<T: Decodable>(json: Data, as clazz: T) {
    do {
        let decoder = JSONDecoder()
        let films = try decoder.decode([T].self, from: json)
    } catch {
        print("An error occurred while parsing JSON")
    }
}

И я называю его так:

self.decode(json: safeData, as: Films.self) //Error thrown here

Мой класс Films выглядит следующим образом:

import Foundation
import CoreData

@objc(Films)
public class Films: NSManagedObject, Decodable {
    enum CodingKeys: String, CodingKey {
        case id
        case title
        case film_description = "description"
        case director
        case producer
        case release_date
        case rt_score
    }

    required public init(from decoder: Decoder) throws {
        guard let context = CodingUserInfoKey(rawValue: "context"),
            let managedObjectContext = decoder.userInfo[context] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "Films", in: managedObjectContext) else {
                fatalError("Failed to decode Films!")
        }
        super.init(entity: entity, insertInto: nil)

        let container = try decoder.container(keyedBy: CodingKeys.self)
        do {
            id = try container.decodeIfPresent(String.self, forKey: .id)
            title = try container.decodeIfPresent(String.self, forKey: .title)
            film_description = try container.decodeIfPresent(String.self, forKey: .film_description)
            director = try container.decodeIfPresent(String.self, forKey: .director)
            producer = try container.decodeIfPresent(String.self, forKey: .producer)
            release_date = try container.decodeIfPresent(String.self, forKey: .release_date)
            rt_score = try container.decodeIfPresent(String.self, forKey: .rt_score)
        } catch let error {
            print(error)
            throw error
        }
    }
}

Но я получаю сообщение об ошибке:

Argument type 'Films.Type' does not conform to expected type 'Decodable'

Я прочитал на форумах Swift следующие темы:

И некоторые говорили, что эти решения сработалидля них, но это та же концепция, что и у меня, и я до сих пор не могу понять, как ее решить.

Как правильно это сделать?

1 Ответ

0 голосов
/ 31 января 2019

Решение было довольно простым:

Эта функция:

private func decode<T: Decodable>(json: Data, as clazz: T) {

Стал:

private func decode<T: Decodable>(json: Data, as clazz: T.Type) {

И это все!Это все, что нужно было сделать

...