I am attempting to create a generic networking function I am looking to make an API handler which will download JSON from the network and convert theme to Swift structs that conform to the Decodable
protocol. Currently I am using explicit types:
struct MyObject : Decodable {
let id : Int
let name : String
}
static fileprivate func makeNetworkRequest(url: URL, completionHandler: @escaping(_ error: Error?, _ myObject: MyObject?) -> ()) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
// handle error
do {
let myNewObject = try JSONDecoder().decode(MyObject.self, from: data!)
completionHandler(nil, myNewObject)
}
catch let error {
completionHandler(error, nil)
return
}
}.resume()
}
I am hoping to create a generic function where I can specify any data type which confirms to Decodable
and have the data object returned in the completion handler. Something along the lines of:
static fileprivate func makeNetworkRequest<T>(url: URL, type: <<<Decodable Type>>>, completionHandler: @escaping(_ error: Error?, _ myObject: <<<Deocable Object>>>?) -> ()) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
// handle error
do {
let myNewObject = try JSONDecoder().decode(<<<Decodable Type>>>.self, from: data!)
completionHandler(nil, myNewObject)
}
catch let error {
completionHandler(error, nil)
return
}
}.resume()
}
However, I can't seem to get the function parameters correct. I do not have a lot of experience working with generics. Any help would be appreciated
You can mimic the declaration of the decode
method of JSONDecoder
:
open func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable
Applying the patter above to your code, the definition should be something like this:
static fileprivate func makeNetworkRequest<T>(url: URL, type: T.Type, completionHandler: @escaping (_ error: Error?, _ myObject: T?) -> ())
where T: Decodable
{
URLSession.shared.dataTask(with: url) { (data, response, error) in
// handle error
do {
let myNewObject = try JSONDecoder().decode(T.self, from: data!)
completionHandler(nil, myNewObject)
} catch let error {
completionHandler(error, nil)
return
}
}.resume()
}
Or you can write it in this way:
static fileprivate func makeNetworkRequest<T: Decodable>(url: URL, type: T.Type, completionHandler: @escaping (_ error: Error?, _ myObject: T?) -> ()) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
// handle error
do {
let myNewObject = try JSONDecoder().decode(T.self, from: data!)
completionHandler(nil, myNewObject)
} catch let error {
completionHandler(error, nil)
return
}
}.resume()
}