SwiftUI Networking

SwiftUI Networking (URLSession)

Almost every modern iOS application needs to connect to the internet to fetch or send data.

Whether you are downloading user profiles, fetching live weather, or loading images, networking is a critical skill.

In Swift, the standard tool for making network requests is URLSession.

Combined with SwiftUI and Swift's modern async/await concurrency features, networking has never been easier.


Defining the Data Model

Before fetching data from an API, you need a Swift structure to hold that data.

Most modern web APIs return data in JSON format.

To convert JSON into a Swift object automatically, your struct must conform to the Codable protocol.

Creating a Codable Model:

import Foundation

// Conforming to Codable allows automatic JSON translation // Conforming to Identifiable allows us to use it in SwiftUI Lists struct User: Codable, Identifiable { let id: Int let name: String let email: String }


Fetching Data with Async/Await

To fetch data, you use URLSession.shared.data(from:).

Because network requests take time, you must use await to pause execution until the server responds.

Once the raw data arrives, you use a JSONDecoder to decode the data into your Codable struct.

The Network Call:

func fetchUsers() async throws -> [User] {
    // 1. Create a valid URL
    guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
        throw URLError(.badURL)
    }
    // 2. Fetch the data asynchronously
    let (data, _) = try await URLSession.shared.data(from: url)
    // 3. Decode the JSON data into an array of Users
    let decodedUsers = try JSONDecoder().decode([User].self, from: data)
    return decodedUsers
}

Triggering the Fetch in SwiftUI

You cannot call an asynchronous function directly from a standard SwiftUI button or onAppear modifier.

Instead, SwiftUI provides the .task modifier.

The .task modifier automatically creates a new concurrent background task the exact moment the view appears on the screen.

Using .task in a View:

import SwiftUI

struct UsersListView: View { @State private var users: [User] = [] var body: some View { List(users) { user in VStack(alignment: .leading) { Text(user.name).font(.headline) Text(user.email).font(.subheadline).foregroundColor(.gray) } } // This triggers automatically when the List appears! .task { do { users = try await fetchUsers() } catch { print("Error fetching users: \(error)") } } } }


If the view disappears before the network request finishes, SwiftUI automatically cancels the .task to save battery life!


Exercise

Which protocol must your Swift struct conform to so that `JSONDecoder` can automatically map JSON data to its properties?