Swift 5 introduces new Result type to handle the result of an asynchronous function. I want to know the way to use this new result type for URLSession.
I have this following code.
func getCategorByAPI()
{
//Base Url is from an static variable
let url = URL(string: URLManager.aPIBaseURL+"category")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
//print("error=\(error)")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
print(json)
}catch
{
print(error)
}
}
task.resume()
}
How can i rewrite this function using swift 5 Result type?
You want to create an enum
that specifies the possible cases in your result (e.g. success or failure). Then you add a completion to your getCategorByAPI()
method that is of type Result<Data, Error>
. From there, inside url session, you will call your completion handler passing in either the data
on .success
or the error
on .failure
.
You can also do cool things like override Result's get()
method and extend Result
to decode your data :D
Check it out:
enum Result<Success, Error: Swift.Error> {
case success(Success)
case failure(Error)
}
// override the Result.get() method
extension Result {
func get() throws -> Success {
switch self {
case .success(let value):
return value
case .failure(let error):
throw error
}
}
}
// use generics - this is where you can decode your data
extension Result where Success == Data {
func decoded<T: Decodable>(using decoder: JSONDecoder = .init()) throws -> T {
let data = try get()
return try decoder.decode(T.self, from: data)
}
}
func getCategorByAPI(completion: (Result<Data, Error>) -> Void)
{
// You might want to stick this into another method
let url = URL(string: URLManager.aPIBaseURL+"category")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
completion(.failure(error))
return
}
if !(200...299).contains(httpResponse.statusCode) && !(httpResponse.statusCode == 304) {
let httpError = // ... convert httpResponse.statusCode into a more readable error
completion(.failure(httpError))
}
if let data = data {
completion(.success(data))
}
}.resume()
}
I haven't tested the above but have something like this implemented in a current project. Here are some articles I read to learn about how to implement:
https://www.hackingwithswift.com/articles/161/how-to-use-result-in-swift
https://medium.com/@pavlepesic/how-to-use-swift-5-result-with-codable-protocol-824c9a951af9
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With