SwiftUI Basics
By the end of this lesson you'll be able to build a real iOS screen by hand: describe it with a View , stack and style the pieces with modifiers, add a tappable button, and make the screen update itself with @State .
Learn SwiftUI Basics in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- • Write a View struct with a body that describes the screen
- • Show content with Text and Image (SF Symbols)
- • Arrange views using VStack , HStack , and ZStack
- • Style anything by chaining modifiers like .font , .padding , .foregroundColor
- • Add a Button that runs an action when tapped
- • Make the UI react automatically to data with @State
🧠 Declarative vs Imperative
In the old imperative style you wrote every step: create a label, set its text, add it to the view, then later find that label and change it by hand each time the data moved. That's a lot of bookkeeping, and bugs creep in when the screen and the data drift out of sync.
SwiftUI is declarative : you write one body that says what the screen looks like for the current state . When the state changes, SwiftUI re-runs body and updates only what actually changed. You describe the what ; the framework handles the how .
1️⃣ Your First View: Text, Image & Modifiers
Everything you see in SwiftUI is a View — a lightweight struct that describes something on screen. Every view struct has a body that returns the content. You customise a view by chaining modifiers : methods like .font() , .foregroundColor() , and .padding() that each return a new, tweaked view. Read this worked example, then build it.
2️⃣ Layout with Stacks
You arrange views with three stacks. VStack lays children out top-to-bottom, HStack left-to-right, and ZStack layers them back-to-front. You nest stacks inside each other to build any layout — no manual constraints required. The spacing: argument controls the gap between children.
Your turn. The view below is almost finished — fill in the three blanks marked ___ using the hints, then preview it.
3️⃣ Buttons & @State : a Reactive Counter
A Button takes a title and an action — a closure (a block of code in { } ) that runs on tap. To make the screen respond , you store data in a property marked @State . A SwiftUI view is a struct that gets rebuilt constantly, so @State tells SwiftUI to keep that value safe between rebuilds and to re-run body automatically whenever it changes. That automatic refresh is what "reactive" means.
Now wire up your own state. Fill in the two blanks so the heart toggles between empty and filled each time the button is tapped:
Common Errors (and the fix)
- "Cannot assign to property: 'self' is immutable" — you tried to change a plain var from inside body . A view is a struct, so its stored values can't be mutated directly. Mark the property @State private var and SwiftUI will let you change it (and redraw the view).
- Modifier order changes the result. .padding().background(.blue) pads first then colours the larger area (a blue border); .background(.blue).padding() colours first then adds clear space. When a layout looks off, swap two modifiers.
- "Type 'MyView' does not conform to protocol 'View'" — you forgot : View on the struct, or body doesn't return a view. Declare struct MyView: View and make body return exactly one view.
- "Function declares an opaque return type 'some View'…" — your body returns two or more views at the top level. Wrap them in a VStack (or other stack) so it returns a single view.
Pro Tips
- 💡 Use the Canvas preview (⌥⌘P) to see changes instantly without building and running.
- 💡 Mark @State as private — that state belongs to this view alone; other views shouldn't reach in.
- 💡 Browse SF Symbols in Apple's free SF Symbols app to find icon names for Image(systemName:) .
📋 Quick Reference — SwiftUI
Piece
Usage
Text
Text("Hi").font(.title)
Image
Image(systemName: "star.fill")
VStack
VStack { Text("A"); Text("B") }
HStack
HStack { ... } (side by side)
ZStack
ZStack { ... } (layered)
Button
Button("Tap") { count += 1 }
@State
@State private var count = 0
padding
.padding() / .padding(16)
Frequently Asked Questions
Mini-Challenge: Quantity Stepper
No blanks this time — just a brief and an outline. Build a small view that shows a number with a minus button on its left and a plus button on its right, where tapping each updates the number live. You'll combine a VStack , an HStack , two Button s, and one @State value.
🎉 Lesson Complete!
- ✅ A screen is a View struct whose body describes the content
- ✅ Text and Image show content; modifiers like .font , .padding , .foregroundColor style it
- ✅ VStack , HStack , and ZStack arrange views — nest them for any layout
- ✅ A Button runs an action closure when tapped
- ✅ @State makes the UI reactive: change the value and SwiftUI redraws automatically
- ✅ SwiftUI is declarative — you describe the result, not the steps
- ✅ Next lesson: Working with APIs — fetch real data and show it in your app
Practice quiz
Every SwiftUI view struct must provide which property?
- render
- content
- body
- view
Answer: body. A View must supply a body property describing its content.
Which protocol must a SwiftUI screen struct conform to?
- Screen
- Renderable
- UIView
- View
Answer: View. A SwiftUI view is a struct conforming to the View protocol.
Which stack arranges its children top to bottom?
- VStack
- HStack
- ZStack
- List
Answer: VStack. VStack lays children out vertically, top to bottom.
Which stack layers views back-to-front?
- VStack
- ZStack
- HStack
- Grid
Answer: ZStack. ZStack overlaps views, layering them back to front.
What makes a stored value redraw the UI when it changes?
- @Binding
- @Published
- @State
- @Environment
Answer: @State. @State stores the value and re-runs body whenever it changes.
What does a Button's action { ... } represent?
- A view
- A modifier
- A protocol
- A closure run on tap
Answer: A closure run on tap. The trailing closure is the action that runs when the button is tapped.
Does the order of modifiers matter?
- Yes, almost always
- No, never
- Only for text
- Only in HStack
Answer: Yes, almost always. Modifiers wrap from the inside out, so order changes the result.
Which call shows an SF Symbol icon?
- Icon("swift")
- Image(systemName: "swift")
- Symbol("swift")
- SFImage("swift")
Answer: Image(systemName: "swift"). Image(systemName:) renders a built-in SF Symbol.
SwiftUI describes the screen for the current state. This style is called...
- Imperative
- Procedural
- Declarative
- Object-oriented
Answer: Declarative. Declarative means you describe the result and the framework builds it.
If body returns two views at the top level, you should...
- Use two bodies
- Mark it @State
- Return nil
- Wrap them in a stack
Answer: Wrap them in a stack. body must return one view, so wrap multiple views in a VStack or similar.
Continue this course
- Previous: Object-Oriented Programming
- Next: Working with APIs