Generic Network Manager using Async Await & Task in SwiftUI
DevTechie Inc
DevTechie Inc
Jan 29, 2023
Generic Network Manager using Async Await & Task in SwiftUI
async/await was introduced by Apple in WWDC 21 with the launch of iOS 15. async/await, transforms asynchronous programming by getting rid of completion handlers which makes the code more readable and more correct.
In this article, we will build a generic network manager. We will combine power of async/await and generic to download JSON from an API call.
Let’s start with a struct called NetworkManager.
struct NetworkManager { }
This struct will have a function called fetch . This is a generic function with placeholder type T, T can be anything as long as it conforms to the Codable protocol. This function takes url string parameter and returns generic type T . Function itself is an async function which can throw an error. This function returns the type T .
URLSession now works with await so we don’t need a completion handler or call resume on URLSession instance. We can simplify the entire call with
await URLSession.shared.data(from: url)
Since URLSession can throw error, we will append try before await.
try await URLSession.shared.data(from: url)
URLSession.Shared.data(from:) returns a tuple with data and response. We will create a variable to hold those values.
let (data, response) = try await URLSession.shared.data(from: url)
Since this is a network call, there are many things that can go wrong so before we proceed, we need to make sure that the response code from the API is correct. The HTTP 200 OK success status response code indicates that the request has succeeded so we will check the status code from response using guard statement.
This API returns lots of items in response but we are only interested in value field which has the joke so based on that we will create our data structure.
struct ChuckNorrisJoke: Codable {
let value: String
}
It’s time to put together our view.
struct DevTechieGenericNetworkManager: View {
@State private var joke: ChuckNorrisJoke? = nil
var body: some View {
NavigationStack {
VStack {
Text(joke?.value ?? "")
.font(.title3)
Button("Show me the joke!") {
}
.buttonStyle(.borderedProminent)
}
.padding()
.navigationTitle("DevTechie")
}
}
}
Inside the Button’s action closure, we will add Task.
Task is a unit of asynchronous work. When we create an instance of Task, we provide a closure which contains the work for that task to perform.
Tasks can start running immediately after creation; we don’t explicitly start or schedule them.
We will call our NetworkManager inside the Task closure.
struct DevTechieGenericNetworkManager: View {
@State private var joke: ChuckNorrisJoke? = nil
var body: some View {
NavigationStack {
VStack {
Text(joke?.value ?? "")
.font(.title3)
Button("Show me the joke!") {
Task {
do {
let chuckNorrisJoke: ChuckNorrisJoke = try await NetworkManager().fetch(from: "https://api.chucknorris.io/jokes/random")
joke = chuckNorrisJoke
} catch {
print(error)
}
}
}
.buttonStyle(.borderedProminent)
}
.padding()
.navigationTitle("DevTechie")
}
}
}
Build and run
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to 👏 and follow 😍. Also subscribe our newsletter at https://www.devtechie.com