Lesson 22 / 25
A First Look at SwiftUI
Understand how Swift language features appear in a small SwiftUI view.
Where the language meets the UI
SwiftUI is Apple's declarative UI framework. A view is a struct conforming to View with a computed body property returning some View (an opaque type), built with result builders inside containers such as VStack, HStack and List. State lives in property wrappers and observation: @State for simple local values, @Binding to share them with child views, and @Observable model classes (from the Observation framework) for app state, usually annotated @MainActor. Views are values that SwiftUI recreates cheaply; when state changes, SwiftUI recomputes body and updates only what changed on screen. Asynchronous loading uses the .task modifier, which is cancelled automatically when the view disappears. Previews with #Preview (a macro) render views live in Xcode. This course covers the language; SwiftUI layout, navigation and data flow deserve their own course, but every concept you have learned (structs, closures, generics, protocols, property wrappers, concurrency) appears in even the smallest SwiftUI screen.
State drives the view
When state changes, SwiftUI recomputes the view description and updates the screen.
A small SwiftUI screen
Structs, opaque types, property wrappers, closures and async loading together.
import SwiftUI
@MainActor
@Observable
final class ProductListModel {
var products: [Product] = []
var isLoading = false
func load() async {
isLoading = true
defer { isLoading = false }
products = (try? await ProductAPI.fetchAll()) ?? []
}
}
struct ProductListView: View {
@State private var model = ProductListModel()
@State private var searchText = ""
private var filtered: [Product] {
searchText.isEmpty ? model.products
: model.products.filter { $0.title.localizedCaseInsensitiveContains(searchText) }
}
var body: some View {
NavigationStack {
List(filtered) { product in
VStack(alignment: .leading) {
Text(product.title).font(.headline)
Text(product.price, format: .currency(code: "INR"))
}
}
.overlay { if model.isLoading { ProgressView() } }
.searchable(text: $searchText)
.navigationTitle("Products")
.task { await model.load() } // cancelled if the view disappears
}
}
}
#Preview { ProductListView() }Keep logic out of body
body may be called often. Keep it a cheap description of the UI, and put loading, validation and business rules in model types that you can unit test without SwiftUI.
Quick check: In SwiftUI, what does `var body: some View` use?
- An existential any View
- A class hierarchy
- An opaque return type: one specific view type hidden from callers
- A property wrapper
Answer
An opaque return type: one specific view type hidden from callers — some View lets the compiler know the exact type while keeping it hidden and efficient.