Reputation: 33
I have method:
func getUsers(completion: @escaping (_ users: [User]?,_ error: String?)->()) { router.request(.getUsers) { (data, response, error) in
var users = [User]()
users = try JSONDecoder().decode(Array<User>.self, from: responseData)
}
But i want to do this function more generic. I tried :
func getUsers<T: Decodable>(completion: @escaping (_ users: [T]?,_ error: String?)->()) { router.request(.getUsers) { (data, response, error) in
var users = [T]()
users = try JSONDecoder().decode(Array<T>.self, from: responseData)
completion(users, nil)
}
But when i call this func users array from escaping closure is [_]. If i just use only T users array is [User.Type] and it does not conform to Decodable so i can do JSONDecoder().decode
. How should it look ?
Upvotes: 0
Views: 1910
Reputation: 684
Hey Hds you have done most of the work correctly, only one missing point that is knowledge about how Decodables work.
An array of Decodable is also Decodable. So what I'm trying to say is you don't need to explicitly mention that you want to decode Array<T>.self
, you can put T.self as long as you have passed to the function that you are expecting an Array<T>.self
so T => Array<T>
So in your case when you call this function and pass [User]
as the generic parameter, T
will be Array<User>.self
while decoding. So here is what the code should look like. I'm not sure if the code will 100% compile because I have some missing components, but it gets the idea across.
func get<T:Deocdable>(completion: @escaping (_ object: T?,_ error: String?) -> ()) {
router.request(.getUsers) { (data, response, error) in
do {
let object = try JSONDecoder().decode(T.self, from: responseData)
} catch {
fatalError("Decoding failed because: ", error.localizedDescription)
}
}
Also I added the do catch block because the try JSONDecoder()
throws.
Also to add on how you should call the method its like the following:
get { (users: [User]?, error) in
}
Hope this helps.
Upvotes: 0
Reputation: 16446
Array< User > is not convertible to '[_]?'
This is because of _ users: [T]? type Optional
Your method is working fine you just have to define optional array.
self.getUsers{ (res:Array<User>?, error) in
}
I have created one similar
func getUsers<T: Decodable>(completion: @escaping (_ users: [T]?,_ error: String?)->()) {
URLSession.shared.dataTask(with: URL(string: "test")!) { (data, res, error) in
guard let resData = data else {completion(nil,"data is nil"); return}
do {
var users = [T]()
users = try JSONDecoder().decode(Array<T>.self, from:resData)
completion(users, nil)
} catch {
completion(nil, error.localizedDescription)
}
}
And call it
self.getUsers{ (res:Array<User>?, error) in
}
Here is struct
struct User :Codable {
var name:String?
}
Upvotes: 3