Networking & Concurrency
The main thread must stay free
iOS draws the UI and handles touches on the main thread. If you run a slow task there — like a network request — the whole app freezes. So networking must happen on a background thread, and only the final UI update returns to the main thread. Modern Swift makes this clean with async/await.
Decoding JSON into types
APIs return JSON. Swift turns JSON into your types automatically if they conform to Decodable:
struct User: Decodable {
let id: Int
let name: String
let email: String
}
Fetching with async/await
func fetchUsers() async throws -> [User] {
let url = URL(string: "https://api.example.com/users")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([User].self, from: data)
}
async marks a function that can pause; await waits for the result without blocking the thread; throws lets it report errors. This reads top-to-bottom like normal code, but runs efficiently in the background.
Calling it and updating the UI
Task {
do {
let users = try await fetchUsers()
await MainActor.run {
self.users = users
self.tableView.reloadData() // UI work on the main thread
}
} catch {
print("Failed: \(error)")
}
}
@MainActor / MainActor.run guarantees UI code runs on the main thread — updating the UI from a background thread is a classic crash.
A quick word on GCD (the older way)
Before async/await, iOS used Grand Central Dispatch (GCD) with dispatch queues. You’ll still see it in existing code:
DispatchQueue.global().async {
// background work
DispatchQueue.main.async {
// back on the main thread for UI
}
}
For new code, prefer async/await — it’s safer and far more readable.
Handling errors and states
Networks fail: no internet, server errors, bad data. Always handle errors and reflect them in the UI (a message, a retry button) rather than letting the app appear frozen or crash.
Common mistakes
- Updating the UI from a background thread (use the main thread /
@MainActor). - Ignoring errors — always
catchand inform the user. - Forgetting the App Transport Security rules (iOS requires HTTPS by default).
Summary: UseURLSession+async/await+Decodableto fetch and parse data off the main thread, then hop back to the main thread (@MainActor) for UI updates. Always handle errors gracefully.