Forms, User Input & Basic Networking (URLSession, async/await)
iOS Development Fundamentals
Chapter 9 · Forms, User Input & Basic Networking
This chapter closes out the course's own core skills with two real, distinct pieces: gathering structured
user input through a real Form, and fetching real data from the internet using Swift's
modern async/await concurrency system.
Form and Input Controls
@State property via the $ projected-value
syntax from Chapter 6 — nothing new here syntactically, just three new real, purpose-built controls:
TextField for text, Toggle for a boolean switch, and Stepper for a
bounded numeric value. Form itself is a real, styled container specifically designed for
this kind of grouped input, giving it the native, sectioned look used throughout Settings and similar
Apple apps.
Swift Concurrency: async/await
Introduced in Swift 5.5 (iOS 15, 2021), async/await is Swift's
real, current way of writing asynchronous code that reads top-to-bottom, like ordinary synchronous code,
instead of nesting completion-handler closures.
A function marked async can pause at an await point without blocking the
thread it runs on — real, genuine cooperative suspension, not a busy-wait.
Fetching Real Data with URLSession
| Piece | Real Role |
|---|---|
URLSession.shared.data(from:) | A real, built-in async method that fetches a URL's data, returning (Data, URLResponse). |
Decodable | A real protocol — conforming lets a type be built directly from JSON by JSONDecoder, matching properties to real JSON keys by name. |
try await | Both real keywords needed together — data(from:) is genuinely async throws, so calling it needs both. |
Calling Async Code from a View: .task
A SwiftUI view's own body can't itself be async — .task {} is the
real, dedicated modifier that bridges the two, running its own async closure when the view first appears.
.task {} is automatically cancelled if the view
disappears before it finishes — real, built-in behavior, not something written manually. Navigating away
from QuoteView mid-fetch doesn't leave a stray network request trying to update a
@State property on a view that no longer exists.
fetchQuote() can genuinely fail — a bad URL, no network, a malformed response — so it's
marked throws, and every real call site needs try plus a surrounding
do/catch (or a further throws of its own) to handle that. Skipping
error handling here isn't optional the way ignoring a return value might be elsewhere.
Hands-On Exercises
Build a Form with a TextField for an email address, a Toggle for "Subscribe to newsletter," and a Stepper for "Number of guests" ranging 1 to 10, each backed by its own real @State property.
Define a struct Joke: Decodable with a real setup: String and punchline: String, write an async throws function fetchJoke() -> Joke following this chapter's own fetchQuote() pattern, and a view using .task to load and display it.
Explain, in your own words, why .task {} automatically cancelling its own work when a view disappears is a genuinely important real safety guarantee, connecting your answer to Chapter 6's own @State externalized-storage mechanism.
Chapter 9 Quick Reference
Form+TextField/Toggle/Stepper— grouped, natively-styled user input, bound via the same@State/$pattern from Chapter 6async/await(Swift 5.5, iOS 15, 2021) — Swift's real, current concurrency system for readable asynchronous codeURLSession.shared.data(from:)— real, built-in async method returning(Data, URLResponse)Decodable+JSONDecoder— real, automatic JSON-to-struct decoding.task {}— bridges async code into a view's own lifecycle, automatically cancelling if the view disappears mid-work