0

I'm trying to make an application in order to learn how to use generics in Swift. So I decided to use Studio Ghibli's API

For this, I do the following:

  1. Create a request to the API
  2. Get the response
  3. Parse the JSON

As in their API, all the information comes with a baseURL equal to https://ghibliapi.herokuapp.com and all the endpoints are baseURL/foo and return an array of whatever info we want. So, for this particular case, I'm trying to use /films and /people.

So, in my head, it would be better to have a generic decoding function that does that and returns an array of the corresponding class that we want to decode.

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")
    }
}

And I call it as:

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

My Films class is as follows:

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
        }
    }
}

But I keep getting an error:

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

I have read in the Swift Forums these topics:

And some have said that those solutions have worked for them, but it's the same concept as mine and I still can't figure out how to solve it.

What would be the correct way to do it?

0

1 Answer 1

2

The solution was quite simple:

This function:

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

Became:

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

And that's it! It's all that was needed to be done

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.