Swift Cheatsheet
Comments
Comments are notes for developers and are ignored by the compiler. Use //
for single-line comments and /* ... */
for multi-line comments.
// This is a single-line comment.
// It's useful for short explanations.
/*
This is a multi-line comment.
It can span several lines and is often
used for longer descriptions or for temporarily
disabling a block of code.
*/
let a = 5 // Comments can also be at the end of a line.
Output
Variable & Constant
Use `var` for data that can change (like a user's score) and `let` for data that is set once and never changes (like a birth date).
Best Practice: Prefer `let` over `var`. This makes your code safer and easier to understand because it prevents accidental changes. Use `var` only when you explicitly need to modify the value later.
var score = 0 // Variable (mutable)
let pi = 3.14 // Constant (immutable)
print("Initial score: \(score)")
score = 10 // Can change because it's var
print("New score: \(score)")
print("Pi value: \(pi)")
Output
New score: 10
Pi value: 3.14
Basic Data Types
Swift needs to know the "type" of data you are storing. Common types include text (`String`), whole numbers (`Int`), decimals (`Double`), true/false (`Bool`), and collections like arrays (`[String]`, `[Int]`).
Note: Swift has powerful type inference, so you often don't need to write the type explicitly. var name = "Alex"
works just fine!
var name: String = "Alex"
var age: Int = 16
var height: Double = 1.75
var isStudent: Bool = true
// Arrays
var teamNames: [String] = ["Warriors", "Lakers", "Bulls"]
var scores: [Int] = [98, 102, 85]
// Print the values to see the output
print("Name: \(name)")
print("Age: \(age)")
print("Height: \(height)m")
print("Is student: \(isStudent)")
print("Team names: \(teamNames)")
print("Scores: \(scores)")
Output
Age: 16
Height: 1.75m
Is student: true
Team names: ["Warriors", "Lakers", "Bulls"]
Scores: [98, 102, 85]
String Interpolation
To mix text with variables or constants in Swift, use a backslash with parentheses: \(yourVariable)
. This works in strings for print statements and SwiftUI Text views.
let name = "Alex"
let age = 16
let score = 95
print("My name is \(name)")
print("I am \(age) years old")
print("\(name) scored \(score) points!")
Output
I am 16 years old
Alex scored 95 points!
If/Else Statements
Use if
, else if
, and else
to make decisions in your code based on certain conditions.
let temperature = 25
if temperature > 30 {
print("It's a hot day!")
} else if temperature < 15 {
print("It's a cold day.")
} else {
print("The weather is mild.")
}
Output
For Loops
for-in
loops allow you to repeat a block of code for each item in a sequence, like an array or a range of numbers.
// Looping through an array
let names = ["Anna", "Alex", "Brian"]
for name in names {
print("Hello, \(name)!")
}
// Looping through a range of numbers
for number in 1...3 {
print("Number is \(number)")
}
Output
Hello, Alex!
Hello, Brian!
Number is 1
Number is 2
Number is 3
Random Numbers & Elements
Swift makes it easy to get random values, whether from a numerical range or from a collection like an array. Use .randomElement() ?? defaultValue
to safely pick from an array.
// Random number in a range (e.g., 1 to 100)
let randomNumber = Int.random(in: 1...100)
print("Random number: \(randomNumber)")
// Random element from an array
let fruits = ["Apple", "Banana", "Cherry"]
let randomFruit = fruits.randomElement() ?? "No fruit!"
print("Random fruit: \(randomFruit)")
let emptyArray: [String] = []
let randomFromEmpty = emptyArray.randomElement() ?? "Default Value"
print("From empty: \(randomFromEmpty)")
Example Output
Random fruit: Apple (or Banana, Cherry)
From empty: Default Value
Functions
Functions are reusable blocks of code that perform a specific task. They can take inputs (parameters) and produce an output (return value).
Note: When calling a function, you use an argument label (like `a:` and `b:` below). Inside the function, you use the parameter name (like `a` and `b`).
// Function with no parameters and no return value
func sayHello() {
print("Hello, World!")
}
sayHello() // Call the function
// Function with parameters and a return value
func add(a: Int, b: Int) -> Int {
return a + b
}
let sum = add(a: 5, b: 3)
print("Sum: \(sum)")
Output
Sum: 8
Switch Statements
A `switch` statement considers a value and compares it against several possible matching patterns. It's a powerful alternative to long `if-else if` chains.
let dayOfWeek = 4
var dayName: String
switch dayOfWeek {
case 1:
dayName = "Sunday"
case 2:
dayName = "Monday"
case 3:
dayName = "Tuesday"
case 4:
dayName = "Wednesday"
default:
dayName = "Other day"
}
print("Day \(dayOfWeek) is \(dayName).")
Output
Dictionaries
A dictionary stores associations between keys of the same type and values of the same type in a collection with no defined ordering.
// Creating and accessing a dictionary
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
print(occupations["Kaylee"] ?? "Unknown")
// Iterating over a dictionary
for (person, job) in occupations {
print("\(person)'s job is \(job).")
}
Output
Malcolm's job is Captain.
Jayne's job is Public Relations.
Kaylee's job is Mechanic.
Optionals
Optionals handle the absence of a value. An optional says either "there is a value, and it equals x" or "there isn’t a value at all" (`nil`). This prevents crashes from using `nil` values.
Recommendation: Use optional binding (`if let`) to safely unwrap and use a value. Use the nil-coalescing operator (`??`) to provide a default value if the optional is `nil`.
var optionalName: String? = "John Appleseed"
// optionalName = nil // It can also be nil
// 1. Optional Binding (Safest)
if let name = optionalName {
print("Hello, \(name)")
} else {
print("Hello, guest!")
}
// 2. Nil-Coalescing Operator (Provides a default)
let greeting = "Hello, \(optionalName ?? "guest")"
print(greeting)
Output
Hello, John Appleseed
Structs vs. Classes
Both are blueprints for objects, but they have a key difference: `Struct`s are value types (copies are made), while `Class`es are reference types (pointers to a shared instance).
Recommendation: Start with `struct`s for your data models. Use a `class` only when you need features like inheritance or when multiple parts of your app must share and modify a single instance of that data.
// Struct (Value Type) - a copy is made
struct User { var name: String }
var user1 = User(name: "Tom")
var user2 = user1
user2.name = "Jerry"
// user1 is unchanged
print("User1: \(user1.name), User2: \(user2.name)")
// Class (Reference Type) - both point to the same object
class Game { var score = 0 }
var game1 = Game()
var game2 = game1
game2.score = 50
// game1 is also changed
print("Game1 Score: \(game1.score), Game2 Score: \(game2.score)")
Output
Game1 Score: 50, Game2 Score: 50
Closures
Closures are self-contained blocks of functionality that can be passed around and used in your code. They can capture and store references to any constants and variables from the context in which they are defined.
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
// Trailing closure syntax
let sortedNames = names.sorted { s1, s2 in
s1 < s2
}
print(sortedNames)
// Shorthand argument names
let reversedNames = names.sorted(by: { $0 > $1 })
print(reversedNames)
Output
["Ewa", "Daniella", "Chris", "Barry", "Alex"]
Codable
The `Codable` protocol is a type alias for the `Encodable` and `Decodable` protocols. It's used to easily encode and decode custom data types to and from external representations like JSON.
struct Landmark: Codable {
var name: String
var foundingYear: Int
}
let jsonString = """
{
"name": "Eiffel Tower",
"foundingYear": 1887
}
"""
let jsonData = Data(jsonString.utf8)
let decoder = JSONDecoder()
if let landmark = try? decoder.decode(Landmark.self, from: jsonData) {
print("\(landmark.name) was founded in \(landmark.foundingYear).")
}
Output
@AppStorage
A property wrapper that reads and writes to `UserDefaults`. It's a convenient way to persist small pieces of data, like user settings, across app launches.
// In a SwiftUI View
struct SettingsView: View {
@AppStorage("username") var username: String = "Anonymous"
var body: some View {
VStack {
Text("Welcome, \(username)!")
Button("Log in") {
username = "Taylor"
}
}
}
}
Output
readLine()
Reads a line of text from the standard input, which is useful for command-line tools. It returns an optional `String`, so you need to unwrap it safely.
print("What is your name?")
if let name = readLine() {
print("Hello, \(name)!")
} else {
print("No input provided.")
}
Example Interaction
User types: Jerry
Hello, Jerry!
SwiftUI Cheatsheet
Layout
VStack
Use `VStack` to arrange views in a vertical line, one on top of the other, like stacking blocks.
VStack(spacing: 10) {
Text("Item 1")
Text("Item 2")
}
Output
HStack
Stacks views horizontally. Good for icons next to text.
HStack(spacing: 8) {
Image(systemName: "star.fill")
Text("My Hobby")
}
Output
Spacer
A `Spacer` is a flexible, invisible view that pushes other views as far apart as possible. It's great for aligning things to the edges.
HStack {
Text("Start")
Spacer()
Text("End")
}
Output
ZStack
Layers views on top of each other. Useful for backgrounds.
ZStack {
Color.purple.ignoresSafeArea() // Background
Text("Content on Top") // Foreground
.foregroundColor(.white)
}
Output
Combining Layouts
VStack
, HStack
, ZStack
, and Spacer
can be nested and combined to create complex user interfaces. This example shows a card-like structure.
ZStack(alignment: .topLeading) {
// Background for the card
Color.gray.opacity(0.1)
.frame(width: 250, height: 150)
.cornerRadius(10)
VStack(alignment: .leading, spacing: 8) {
HStack {
Image(systemName: "star.fill")
.foregroundColor(.yellow)
Text("Featured Item")
.font(.headline)
Spacer() // Pushes content left
}
Text("This item uses ZStack, VStack, HStack, and Spacer.")
.font(.caption)
}
.padding() // Padding inside the VStack
}
.frame(width: 250, height: 150) // Frame for ZStack
Output
This item uses ZStack, VStack, HStack, and Spacer.
ScrollView
A scrollable view. You can specify the scroll direction (`.vertical` or `.horizontal`). It's great for content that doesn't fit on one screen.
ScrollView {
VStack(alignment: .leading, spacing: 10) {
ForEach(0..50) { index in
Text("Row \(index)")
}
}
}
.frame(height: 200) // Give the ScrollView a fixed height
Output
Row 0
Row 1
Row 2
...
Row 49
Views & Modifiers
Text("Hello")
Displays text on the screen.
Text("Your Name")
.font(.title)
Output
Image("imageName")
Displays an image from your project's "Assets" folder.
Image("avatar1") // "avatar1" must be in Assets
.resizable()
.frame(width: 100, height: 100)
Output
100x100
Image(systemName: "...")
Displays an icon from Apple's SF Symbols library. These are vector-based and adapt well to different sizes and styles.
// Displaying various SF Symbols
VStack(spacing: 15) {
Image(systemName: "star.fill")
Image(systemName: "heart.circle.fill")
Image(systemName: "trash.slash.fill")
Image(systemName: "folder.badge.plus")
}
.font(.largeTitle) // Apply a consistent size
.foregroundColor(.blue) // Apply a consistent color
Output
AsyncImage
Loads and displays an image from a URL asynchronously. It shows a placeholder while the image is loading.
AsyncImage(url: URL(string: "https://picsum.photos/id/237/200/300")) { image in
image.resizable().scaledToFit()
} placeholder: {
ProgressView() // Shows a loading spinner
}
.frame(width: 100, height: 100)
Output
(Image loaded from URL)
List { ... }
Creates a scrolling list of items. Often contains HStack
s.
List {
HStack {
Image(systemName: "music.note")
Text("Music")
}
HStack {
Image(systemName: "film.fill")
Text("Movies")
}
}
.frame(height: 100) // Give the list a size
.listStyle(.plain)
Output (Simplified)
ProgressView
Displays a view that shows the progress of a task over time. It can be indeterminate (a spinner) or determinate (a progress bar).
VStack(spacing: 20) {
// Indeterminate (spinner)
ProgressView()
// Determinate (progress bar)
ProgressView(value: 0.75) {
Text("Loading...")
}
}
Output
Loading...
Advanced Views & Controls
Shapes (Circle, Rectangle)
SwiftUI provides several built-in shapes that you can use as views. They can be styled with modifiers like `.fill`, `.stroke`, and `.frame`.
HStack(spacing: 20) {
Circle()
.fill(Color.blue)
.frame(width: 80, height: 80)
Rectangle()
.stroke(Color.red, lineWidth: 5)
.frame(width: 120, height: 80)
}
Output
MapKit Integration
Display an interactive map by importing `MapKit` and using the `Map` view. You can specify a coordinate region to display.
import MapKit
struct MapView: View {
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 10.729, longitude: 106.694),
span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
)
var body: some View {
Map(coordinateRegion: $region)
.frame(height: 200)
}
}
Output

(Simulated Map View)
Data Flow & Architecture
MVVM Design Pattern
The Model-View-ViewModel (MVVM) pattern separates your code into three parts: the Model (data), the View (UI), and the ViewModel (business logic), making your code cleaner and easier to manage.
// Model
struct Counter { var value = 0 }
// ViewModel
class CounterViewModel: ObservableObject {
@Published private(set) var counter = Counter()
func increment() { counter.value += 1 }
}
// View
struct CounterView: View {
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count: \(viewModel.counter.value)")
Button("Increment") { viewModel.increment() }
}
}
}
Observation Framework (@Observable)
Introduced in iOS 17, the `@Observable` macro simplifies state management by automatically making class properties observable, removing the need for `@Published`.
import Observation
@Observable
class Account {
var balance: Double = 100.0
}
struct AccountView: View {
@State private var account = Account()
var body: some View {
Text("Balance: $\(account.balance)")
}
}
SwiftData
SwiftData is a powerful and expressive framework for data persistence. Use the `@Model` macro to turn a Swift class into a stored model, and `@Query` to fetch data.
import SwiftData
@Model
class DataItem {
var name: String
init(name: String) { self.name = name }
}
struct DataListView: View {
@Query var items: [DataItem]
var body: some View {
List(items) { item in
Text(item.name)
}
}
}
CoreData
CoreData is a mature and robust framework for managing a model layer. It can persist data locally on the device. It requires more setup than SwiftData but is powerful for complex data models.
// In DataController
let container = NSPersistentContainer(name: "Model")
// In a SwiftUI View
@Environment(\.managedObjectContext) var moc
@FetchRequest(sortDescriptors: []) var items: FetchedResults-
Button("Add Item") {
let newItem = Item(context: moc)
newItem.name = "New Item"
try? moc.save()
}
@Binding
Creates a two-way connection between a property that stores data, and a view that displays and changes it. It allows a child view to modify a `@State` property owned by its parent.
struct ParentView: View {
@State private var isToggleOn = false
var body: some View { ChildView(isToggleOn: $isToggleOn) }
}
struct ChildView: View {
@Binding var isToggleOn: Bool
var body: some View { Toggle("Is On", isOn: $isToggleOn) }
}
@StateObject vs. @ObservedObject
Both are used for complex reference-type data (classes). Use `@StateObject` when a view creates and owns the object. Use `@ObservedObject` when a view receives the object from a parent view.
class UserProgress: ObservableObject {
@Published var score = 0
}
struct GameView: View {
// GameView creates and owns the progress object
@StateObject private var progress = UserProgress()
var body: some View {
VStack {
Text("Score: \(progress.score)")
// Pass the object to a child view
ScoreButton(progress: progress)
}
}
}
struct ScoreButton: View {
// ScoreButton receives and observes the object
@ObservedObject var progress: UserProgress
var body: some View {
Button("Increase Score") {
progress.score += 10
}
}
}
@EnvironmentObject
Injects an object into the environment, making it accessible to any child view in the hierarchy without passing it down manually. Useful for shared data like user settings or themes.
// Inject the object in the root view of the app
// SceneDelegate.swift or App.swift
let settings = UserSettings()
ContentView().environmentObject(settings)
// Any child view can now access it
struct SomeChildView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
Text("Username: \(settings.username)")
}
}
Firebase Authentication
Integrate secure authentication into your app using Firebase. It supports email & password, phone, and social logins like Google and Facebook.
import Firebase
// Sign Up a new user
Auth.auth().createUser(withEmail: email, password: password)
// Sign In an existing user
Auth.auth().signIn(withEmail: email, password: password)
Functionality
Cloud Firestore
A flexible, scalable NoSQL cloud database to store and sync data for client- and server-side development. Data is synced in real-time across all clients.
import FirebaseFirestore
let db = Firestore.firestore()
// Add a new document to a collection
db.collection("users").addDocument(data: ["name": "Ada"])
// Read documents from a collection
db.collection("users").getDocuments() { (querySnapshot, err) in
// ... loop through documents
}
Functionality
Common Modifiers (Your Superpowers!)
Modifier Order Matters
The order in which you apply modifiers is important. A modifier usually wraps the view and returns a new, modified view. Applying them in a different order can produce a different result.
// Example 1: Padding then Background
Text("Hello")
.padding()
.background(Color.red)
// Example 2: Background then Padding
Text("Hello")
.background(Color.red)
.padding()
Output
Custom Fonts
To use custom fonts, add the font file (e.g., `.ttf` or `.otf`) to your project, register it in your `Info.plist` file, and then use it with the `.font(.custom(...))` modifier.
// 1. Add font file to project
// 2. Add "Fonts provided by application" key to Info.plist
// 3. Use in your view
Text("Custom Font!")
.font(.custom("YourFontName-Regular", size: 24))
ViewModifier
Create reusable sets of modifiers by defining a custom `ViewModifier`. This helps keep your code clean and consistent, especially for styles you apply often, like for buttons or titles.
struct PrimaryTitle: ViewModifier {
func body(content: Content) -> some View {
content
.font(.largeTitle)
.foregroundColor(.blue)
.padding()
.background(Color.gray.opacity(0.2))
.cornerRadius(10)
}
}
// Usage
Text("Main Title")
.modifier(PrimaryTitle())
.font()
Changes text font and size. E.g.,.font(.title)
,.font(.headline)
,.font(.system(size: 32, weight: .bold))
,.font(.custom("Corinthia-Regular", size: 70))
,.font(.custom("Silkscreen-Regular", size: 40))
,.font(.custom("Sacramento-Regular", size: 50))
.
.foregroundColor()
Changes text or icon color. E.g.,.foregroundColor(.blue)
,.foregroundColor(Color.white)
.
.background()
Puts a colored background. E.g.,.background(Color.black.opacity(0.5))
.
.padding()
Adds space around a view. E.g.,.padding()
(all sides),.padding(.horizontal)
(left & right),.padding([.top, .leading], 10)
(specific sides & amount).
.cornerRadius()
Rounds the corners. E.g.,.cornerRadius(15)
.
.frame()
Gives a view a fixed size. E.g.,.frame(width: 150, height: 150)
,.frame(height: 180)
.
.resizable()
(For Images) Allows the image to be resized.
.aspectRatio() / .scaledToFill()
(For Images) Controls how an image fills its frame. E.g.,.aspectRatio(contentMode: .fill)
.
.clipShape()
(For Images) Clips the view into a shape. E.g.,.clipShape(Circle())
.
.overlay()
Layers another view on top, often for borders. E.g.,.overlay(Circle().stroke(Color.white, lineWidth: 4))
.
.shadow()
Adds a drop shadow. E.g.,.shadow(radius: 10)
.
.offset()
Moves a view from its original position without affecting the layout of other views. E.g.,.offset(x: 20, y: -10)
moves the view 20 points right and 10 points up.
.position()
Places the center of a view at a specific coordinate within its parent's coordinate space. E.g.,.position(x: 100, y: 150)
.
For dynamic centering, use GeometryReader
to get the parent's size:
GeometryReader { geometry in
Text("Centered")
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
}
.listStyle()
(For Lists) Changes list appearance. E.g.,.listStyle(.plain)
.
.ignoresSafeArea()
(For Colors/Backgrounds) Makes it fill the whole screen, even under notches. E.g.,Color.black.ignoresSafeArea()
.
Modifier Combo: Styled Button Text
Combining modifiers to create a common button style with padding, background, corner radius, and text styling.
Text("Tap Me!")
.font(.headline)
.foregroundColor(.white)
.padding() // Add padding around the text
.background(Color.blue) // Blue background
.cornerRadius(10) // Rounded corners
.shadow(radius: 5) // Subtle shadow
Output
Modifier Combo: Circular Profile Image
Common pattern for profile images: resizable, specific frame, circular clip, and an overlay border.
Image("avatar1") // Assuming "avatar1" is in Assets
.resizable()
.scaledToFill() // Fill the frame, may crop
.frame(width: 100, height: 100)
.clipShape(Circle()) // Clip to a circle
.overlay( // Add a border
Circle().stroke(Color.orange, lineWidth: 4)
)
.shadow(radius: 7)
Output
Circular
Modifier Combo: Card View
Creating a card-like appearance using padding, background, corner radius, and shadow on a VStack.
VStack(alignment: .leading) {
Text("Card Title")
.font(.title2).bold()
.foregroundColor(.primary) // Use primary text color
Text("This is some descriptive text for the card content. It explains what the card is about.")
.font(.body)
.foregroundColor(.secondary) // Use secondary text color for subtlety
}
.padding() // Inner padding for content
.background(Color.gray.opacity(0.1)) // Light gray background, slightly transparent
.cornerRadius(12) // Rounded corners for the card
.shadow(radius: 5) // Default shadow with a radius
.padding() // Outer padding to see shadow
Output
Card Title
This is some descriptive text for the card content. It explains what the card is about.
Visual & Transformational Effects
.opacity()
Controls the transparency of a view. A value of 1.0 is fully opaque, while 0.0 is fully transparent.
Text("Faded Text")
.opacity(0.5)
Output
.rotationEffect()
Rotates a view by a specified angle. You can specify the angle in degrees or radians.
Text("Rotated")
.rotationEffect(.degrees(-45))
Output
.scaleEffect()
Scales a view larger or smaller. A value of 1.0 is the original size.
Text("Bigger")
.scaleEffect(1.5)
Output
.blur()
Applies a Gaussian blur effect to a view. The radius determines the intensity of the blur.
Text("Blurred")
.blur(radius: 3.0)
Output
Gradients
Create smooth transitions between colors. Common types include `LinearGradient`, `RadialGradient`, and `AngularGradient`.
VStack(spacing: 10) {
LinearGradient(colors: [.blue, .white], startPoint: .top, endPoint: .bottom)
RadialGradient(colors: [.yellow, .red], center: .center, startRadius: 5, endRadius: 50)
AngularGradient(colors: [.green, .blue], center: .center)
}
.frame(height: 150)
Output
Interactivity & Animation
State & Actions
Use `@State` to store a value that can change. A `Button` can change that value, and SwiftUI will automatically update the view.
@State private var tapCount = 0
VStack(spacing: 15) {
Text("Taps: \(tapCount)")
Button("Tap Me") {
tapCount += 1
}
}
Interactive Output
.onTapGesture { ... }
Makes any view tappable. Code inside the curly braces runs on tap.
// Add to an Image or Text view
Image("avatar1")
.onTapGesture {
// Action: what happens when tapped
currentQuote = quotes.randomElement() ?? "Hmm..."
}
Animation
SwiftUI provides two main ways to create animations: implicit animations using the `.animation()` modifier, and explicit animations using the `withAnimation` block.
@State private var isRotated = false
// Implicit Animation
Image(systemName: "arrow.up")
.rotationEffect(isRotated ? .degrees(180) : .zero)
.animation(.easeInOut, value: isRotated)
// Explicit Animation
Button("Rotate") {
withAnimation {
isRotated.toggle()
}
}
.onAppear() / .onDisappear()
Triggers an action when a view becomes visible or is removed from the view hierarchy. Useful for loading data or cleanup.
Text("My View")
.onAppear {
print("View appeared!")
}
.onDisappear {
print("View disappeared!")
}
Output
.sheet() & .presentationDetents()
Presents a view modally. Use `.presentationDetents()` to specify the height of the sheet, such as half-screen (`.medium`) or full-screen (`.large`).
@State private var isShowingSheet = false
Button("Show Sheet") {
isShowingSheet = true
}
.sheet(isPresented: $isShowingSheet) {
MySheetView()
.presentationDetents([.medium, .large])
}
Output
.alert()
Displays an alert message to the user, also controlled by a boolean @State
variable.
@State private var isShowingAlert = false
Button("Show Alert") {
isShowingAlert = true
}
.alert("Important Message", isPresented: $isShowingAlert) {
Button("OK", role: .cancel) { }
}
Output
Navigation
NavigationView & NavigationLink
`NavigationView` creates a navigation bar. `NavigationLink` is a special button that pushes a new view onto the screen.
Note: `NavigationView` is deprecated in iOS 16+. It's recommended to use `NavigationStack` for new projects for more robust navigation control.
NavigationView {
VStack {
NavigationLink(destination: Text("Detail View")) {
Text("Go to Detail")
}
}
.navigationTitle("Master View")
}
Output: Master → Detail View
NavigationStack
The modern way to handle navigation, introduced in iOS 16. It provides a more flexible and programmatic way to manage a stack of views.
NavigationStack {
List(destinations) { destination in
NavigationLink(destination.name, value: destination)
}
.navigationDestination(for: Destination.self) { destination in
DetailView(destination: destination)
}
.navigationTitle("Destinations")
}
Modal Presentation with .sheet()
Presents a view modally over the current one. This is a common way to handle self-contained tasks like logging in, creating a new item, or showing settings, without adding to the main navigation stack.
@State private var isShowingLoginSheet = false
VStack {
Button("Log In") {
isShowingLoginSheet = true
}
}
.sheet(isPresented: $isShowingLoginSheet) {
// The view to present modally
LoginView()
}