SwiftUI Introduction
SwiftUI Introduction
Build interfaces declaratively with views, state, and data-driven updates using SwiftUI.
What is SwiftUI?
SwiftUI is Apple's modern UI framework for building apps on iOS, iPadOS, macOS, watchOS, and tvOS.
It is declarative: you describe what the UI should look like, and SwiftUI updates it when your data changes.
Why SwiftUI?
- Declarative syntax and reactive updates with
@State,@Binding, andObservableObject. - Unified API across Apple platforms.
- Live previews and fast iteration in Xcode.
Building our First "App"
First, you'll build a simple counter view (ContentView) shown by the app entry (App.swift).
Next, you'll refactor the same UI but move its state into a view model (ObservableObject), which scales better in real apps.
Step 1: Basic Example
Syntax: Use @State for local state and bind it to controls (e.g., Button); render with VStack/Text.
Example
import SwiftUI
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 12) {
Text("Count: \(count)")
Button("Increment") { count += 1 }
}
.padding()
}
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
This example shows a simple counter using @State and a button inside a VStack.
About ContentView.swift: In SwiftUI, views live in ordinary .swift files.
The starter view is typically named ContentView.swift, and the app's entry point (App.swift) shows it in a WindowGroup.
Step 2: State with ObservableObject
Use ObservableObject to hold shared state, and @StateObject in the creating view to own its lifecycle.
Views update automatically when @Published properties change.
Syntax: class VM: ObservableObject { @Published var count }, @StateObject private var vm = VM(), bind UI to vm.count.
This example refactors the basic counter above.
The UI and behavior are the same (a counter label and button), but the state now lives in a CounterModel view model managed by @StateObject. This pattern scales better as your app grows.
Example
import SwiftUI
import Combine
class CounterModel: ObservableObject {
@Published var count = 0
func increment() { count += 1 }
}
import SwiftUI
struct ContentView: View {
@StateObject private var model = CounterModel()
var body: some View {
VStack(spacing: 12) {
Text("Count: \(model.count)")
Button("Increment") { model.increment() }
}
.padding()
}
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
This example promotes state into a ViewModel and updates the UI via @Published changes observed by the view.
Platform look: SwiftUI adapts controls to the platform. On iOS the button appears as blue text; on macOS it's a bordered push button. The behavior is the same.
See iOS style in Xcode: run an iOS App target (iPhone simulator). If you're in a macOS App and want a text-style button, add .buttonStyle(.plain) to the button.
Run Examples in Xcode
Standard workflow (used in this tutorial)
Every example is organized into three files so you can run it as a small app:
- Demo.swift: The example's main code (view and/or supporting types).
- ContentView.swift: Shows the demo (references types from
Demo.swift). - App.swift: Stable app entry with
WindowGroup { ContentView() }.
Tip: In your own Xcode project, keep a single ContentView. If you already have one from a previous example, reuse that file and update its body for the new demo. Alternatively, create a chooser menu and navigate to uniquely named demo views.
Optional: Canvas Preview
You can also run any example via Xcode's Canvas Preview without changing your app entry point.
- Create a View file: In Xcode choose File > New > File... > SwiftUI View. Name it (for example,
FrameDemo.swift) and paste the example view's code into it. - Add a Preview: Ensure the file has a preview. Use either a
PreviewProvideror the#Previewmacro.
import SwiftUI
struct FrameDemo_Previews: PreviewProvider {
static var previews: some View { FrameDemo() }
}
import SwiftUI
#Preview { FrameDemo() }
- Open the Canvas: With the file selected, choose Editor > Canvas (or click the Canvas button). If you don't see the preview, build the project once.
- Run the Preview: Click Resume / Play in the Canvas. Edits to the code will refresh the preview. Use the device picker to switch iPhone/iPad models.
- Interact: Previews are interactive—tap buttons, type into fields, etc.
Troubleshooting: If the Canvas won't load, try a project Build, then Clean Build Folder. Make sure the target platform is iOS and the file imports SwiftUI.
Run on Simulator: You can also run any example on the simulator by temporarily setting WindowGroup { ExampleView() } in App.swift, or by navigating to the example from a simple in-app menu.