I'm trying to create a protocol that has a function with generic parameters.
protocol APIRequest {
static func fetchData<T: Codable>(completion: @escaping(T?, NetworkError?) -> Void)
}
then I have a struct that conforms the protocol
static func fetchData<Ztar: Codable>(completion: @escaping (Ztar?, NetworkError?) -> Void) {
let url = URLConstructor.url(scheme: "https", host: "swapi.dev" , path: "/api")
guard let url = url else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else {
completion(nil, NetworkError.badResponse)
return
}
do {
let decoder = JSONDecoder()
let object = try decoder.decode(Ztar.self, from: data)
completion(object, nil)
} catch {
print(error)
}
}
task.resume()
}
but I'm not sure if that implementation of the type of the generic is correct because in my ViewController
I'm receiving the error Generic parameter 'Ztar' could not be inferred
NetworkManager.fetchData { star, error in
}
Can someone explain What I'm doing wrong?
It's not possible to implement this correctly. What type is Ztar? How would the compiler know? You've written "fetchData
will fetch some kind of data, out of all the infinitely possible kinds of data in the universe, and you, the compiler, should decode it." That's not possible.
Instead, the way this would generally be written is:
fetchData<T: Codable>(ofType: T.Type, completion: @escaping (Result<T, NetworkError>) -> Void)
And then you would need to pass the type you expect as the first parameter:
fetchData(ofType: Record.self) { resultRecord in ... }
If you don't know what type Ztar is, how can the compiler?
(Note that you should almost never use (T?, Error?)
as a type. That says "maybe T, maybe Error, maybe neither, maybe both." You almost always mean Result<T, Error>
instead. That says "either T or Error.")