Basics, Optionals, Collections, Closures, Protocols & Generics, SwiftUI, Concurrency — complete Swift and iOS development reference.
// ── Variables & Constants ──
var name: String = "Alice" // variable (mutable)
let age: Int = 30 // constant (immutable)
var score = 95.5 // type inference
let pi = 3.14159
// String interpolation
let greeting = "Hello, \(name)! You are \(age) years old."
// Multi-line strings
let multiline = """
Line 1
Line 2
Line 3
"""
// ── Basic Types ──
let integer: Int = 42
let unsignedInt: UInt = 42
let floating: Double = 3.14
let float32: Float = 3.14
let isTrue: Bool = true
let letter: Character = "A"
let emoji: Character = "🦀"
// Type alias
typealias Age = Int
let myAge: Age = 25
// ── Tuples ──
let httpError = (404, "Not Found")
let (statusCode, statusMessage) = httpError
let (code, _) = httpError // ignore with _
let error = (code: 404, message: "Not Found") // named
// ── Type Conversion ──
let label = "Width: "
let width = 94
let widthLabel = label + String(width)
let widthLabel2 = "Width: \(width)"
let num = Int(3.14) // Double → Int (truncates)
let piStr = String(pi) // Double → String
let intFromStr = Int("42")! // String → Int (force unwrap)
// ── Optionals ──
var optionalName: String? = "Alice" // String? = Optional<String>
optionalName = nil // no value
print(optionalName ?? "Unknown") // nil coalescing
// ── Collections ──
var fruits = ["apple", "banana", "cherry"] // Array<String>
fruits.append("date")
fruits += ["elderberry"]
fruits.insert("avocado", at: 1)
fruits.remove(at: 2)
var scores: [String: Int] = ["alice": 95, "bob": 87] // Dictionary
scores["charlie"] = 75
scores.updateValue(90, forKey: "alice")
var unique: Set<Int> = [1, 2, 3, 3, 4] // Set<Int>
unique.insert(5)
unique.contains(3)// ── If / Switch ──
let temperature = 30
if temperature > 35 {
print("Hot")
} else if temperature > 20 {
print("Warm")
} else {
print("Cold")
}
// if let — optional binding
if let unwrapped = optionalName {
print("Hello, \(unwrapped)")
}
// guard let — early return
func process(name: String?) {
guard let name = name else { return }
print("Processing \(name)")
}
// Switch — exhaustive, no fall-through (use fallthrough keyword)
let grade = "B"
switch grade {
case "A": print("Excellent")
case "B", "C": print("Good")
case "D": print("Pass")
default: print("Fail")
}
// Range matching
switch score {
case 90...100: print("A")
case 80..<90: print("B")
case 0..<80: print("Below average")
default: print("Invalid")
}
// Tuple matching
switch httpError {
case (200, _): print("Success")
case (404, let msg): print("Not found: \(msg)")
case let (code, _): print("Code \(code)")
}
// ── Loops ──
for i in 0..<5 { print(i) } // 0, 1, 2, 3, 4
for i in 0...5 { print(i) } // 0, 1, 2, 3, 4, 5
for i in stride(from: 0, to: 10, by: 2) { print(i) } // 0, 2, 4, 6, 8
for fruit in fruits { print(fruit) }
for (key, value) in scores { print("\(key): \(value)") }
while condition { /* ... */ }
repeat { /* ... */ } while condition // do-while equivalent| Type | Default Size | Notes |
|---|---|---|
| Int | 64-bit | Platform-dependent (32/64) |
| UInt | 64-bit | Unsigned integer |
| Float | 32-bit | Single precision |
| Double | 64-bit | Double precision (default) |
| Bool | 1 byte | true / false |
| String | Heap | Unicode-compliant, copy-on-write |
| Character | Variable | Extended grapheme cluster |
| Collection | Syntax | Ordered | Unique |
|---|---|---|---|
| Array | [Type] | Yes | No |
| Set | Set<Type> | No | Yes |
| Dictionary | [Key: Value] | No (ordered insertion) | Keys unique |
let by default — only use var when mutation is needed. The compiler optimizes immutability. Use guard let instead of if let when unwrapping optionals at the start of a function — it keeps the happy path unindented.// ── What Are Optionals? ──
// An optional represents either a value or nil (absence of value)
var name: String? = "Alice" // Optional<String>
name = nil // no value
// Non-optional can NEVER be nil
var definitely: String = "Hello"
// definitely = nil // COMPILE ERROR!
// ── Unwrapping Methods ──
// 1. Force unwrap (!) — dangerous, crashes if nil
let forced: String = name! // "Alice" or CRASH
// 2. Optional binding (if let / guard let)
if let unwrapped = name {
print(unwrapped) // safe
} else {
print("name is nil")
}
// 3. Nil coalescing (??) — provide default
let displayName = name ?? "Anonymous" // "Alice" or "Anonymous"
// 4. Optional chaining (?.) — safe access
struct User { var address: Address? }
struct Address { var street: String? }
let user: User? = User(address: Address(street: "Main St"))
// Safe deep access — returns Optional
let street = user?.address?.street // Optional<String>
// 5. Implicitly unwrapped optionals (String!) — assume non-nil
// Used for IBOutlets and other initialization patterns
@IBOutlet var label: UILabel!
// 6. map / flatMap on optionals
let count = name.map { $0.count } // Optional<Int>
let upper = name.map { $0.uppercased() }
// ── guard let ──
func greet(person: String?) {
guard let name = person else {
print("No name provided")
return // must exit scope
}
// name is available here as non-optional
print("Hello, \(name)!")
}
// ── guard let with multiple bindings ──
func processUser(id: Int?, email: String?) {
guard let id = id, let email = email else {
print("Missing data")
return
}
print("User \(id): \(email)")
}// ── Optional Patterns ──
// Optional pattern in if case
let optionalNum: Int? = 42
if case let x? = optionalNum {
print("Contains \(x)")
}
// Optional pattern in for loop
let optionalNumbers: [Int?] = [1, nil, 3, nil, 5]
for case let number? in optionalNumbers {
print(number) // 1, 3, 5 (skips nil)
}
// Optional pattern in switch
func handle(response: (code: Int, message: String?)) {
switch response {
case (200, let msg?): print("OK: \(msg)")
case (200, nil): print("OK: no message")
case (404, _): print("Not Found")
case let (code, _): print("Error \(code)")
}
}
// ── try? — converts throwing to optional ──
func loadData() throws -> Data { /* ... */ }
let data = try? loadData() // Data? — nil on error
// ── try! — force try (rethrows on error)
// Deprecated: use try! sparingly
// ── compactMap — filter nil from arrays ──
let numbers: [String?] = ["1", nil, "3", "four", "5"]
let ints = numbers.compactMap { Int($0) }
// [1, 3, 5]
// ── Optional with default dictionary value ──
var dict: [String: [Int]] = ["even": [2, 4, 6]]
dict["odd", default: []].append(7)
// dict["odd"] is now [7]| Method | Syntax | When Nil |
|---|---|---|
| Force unwrap | opt! | Crashes (avoid!) |
| Optional binding | if let x = opt | Skip else block |
| Guard let | guard let x = opt | Early return |
| Nil coalescing | opt ?? default | Returns default |
| Optional chain | opt?.method() | Returns nil |
| map | opt.map { ... } | Returns nil |
| try? | try? throwing() | Returns nil |
if let, guard let, ??, or ?. instead. The only acceptable use of ! is with IBOutlets which are guaranteed to be set before use.// ── Arrays ──
var numbers = [1, 2, 3, 4, 5]
var empty: [String] = []
var defaulted = Array(repeating: 0, count: 10) // [0, 0, ..., 0]
// Modify
numbers.append(6)
numbers.insert(0, at: 0)
numbers.remove(at: 2)
numbers.removeFirst(); numbers.removeLast()
numbers.removeAll(where: { $0 < 3 })
numbers.swapAt(0, 4)
numbers.replaceSubrange(1...3, with: [10, 20, 30])
// Access
numbers[0]
numbers[1...3] // ArraySlice (use Array() to convert)
numbers.first; numbers.last
numbers.isEmpty; numbers.count
// Sort
numbers.sorted() // returns new sorted array
numbers.sort() // in-place sort
numbers.sorted(by: > ) // descending
numbers.sorted { $0.count > $1.count }
// Functional methods
numbers.map { $0 * 2 } // [2, 4, 6, 8, 10]
numbers.filter { $0 > 3 } // [4, 5]
numbers.reduce(0) { $0 + $1 } // 15 (sum)
numbers.contains(3) // true
numbers.firstIndex(of: 3)
numbers.prefix(3) // first 3 elements
numbers.suffix(2) // last 2 elements
numbers.dropFirst(2)
numbers.dropLast(1)
numbers.flatMap { Array(repeating: $0, count: $0) }
numbers.forEach { print($0) }
numbers.shuffled() // random order
numbers.randomElement() // Optional random
numbers.min(); numbers.max()
numbers.indices // 0..<count
// ── 2D Arrays ──
var matrix = [[1, 2], [3, 4], [5, 6]]
let flat = matrix.flatMap { $0 } // [1, 2, 3, 4, 5, 6]
let transposed = matrix.transposed()// ── Dictionaries ──
var scores: [String: Int] = ["alice": 95, "bob": 87, "charlie": 72]
// Modify
scores["dave"] = 90 // insert/update
scores.updateValue(100, forKey: "alice") // update
scores.removeValue(forKey: "bob") // remove, returns old value
scores.merge(["eve": 88]) { (old, _) in old } // merge keeping old
// Access
scores["alice"] // Int? (optional)
scores.keys // Dictionary.Keys
scores.values // Dictionary.Values
scores.count; scores.isEmpty
// Iterate
for (name, score) in scores { print("\(name): \(score)") }
for name in scores.keys { print(name) }
// Transform
let pass = scores.filter { $0.value >= 80 }
let names = scores.map { $0.key }
let formatted = scores.mapValues { "Score: \($0)" }
// Group
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let grouped = Dictionary(grouping: numbers, by: { $0 % 2 == 0 ? "even" : "odd" })
// ["odd": [1, 3, 5, 7, 9], "even": [2, 4, 6, 8, 10]]
// Default value
scores["frank", default: 0] // returns 0 if missing
scores["frank", default: 0] += 5 // updates if exists, sets if not
// ── Sets ──
var genres: Set<String> = ["Rock", "Jazz", "Classical"]
genres.insert("Pop")
genres.remove("Jazz")
genres.contains("Rock") // true
// Set operations
let a: Set = [1, 2, 3, 4]
let b: Set = [3, 4, 5, 6]
a.union(b) // [1, 2, 3, 4, 5, 6]
a.intersection(b) // [3, 4]
a.symmetricDifference(b) // [1, 2, 5, 6]
a.subtracting(b) // [1, 2]
a.isSubset(of: b) // false
a.isSuperset(of: b) // false
a.isDisjoint(with: [7, 8]) // true| Operation | Array | Dictionary | Set |
|---|---|---|---|
| Access by index/key | O(1) | O(1)* | N/A |
| Insert | O(n)* | O(1)* | O(1)* |
| Remove | O(n) | O(1)* | O(1)* |
| Search | O(n) | O(1)* | O(1)* |
| Sort | O(n log n) | N/A | N/A |
// ── Closure Syntax ──
// Full: { (params) -> ReturnType in body }
// Optimized: { params in body }
// Shorthand: { $0 + $1 } ($0, $1 = shorthand args)
let greet = { (name: String) -> String in
return "Hello, \(name)!"
}
print(greet("Alice")) // "Hello, Alice!"
// Shorthand argument names
let add = { (a: Int, b: Int) -> Int in return a + b }
let shortAdd: (Int, Int) -> Int = { $0 + $1 }
// Closures capture variables from their surrounding context
func makeIncrementer(amount: Int) -> () -> Int {
var total = 0
return { // captures 'total' and 'amount'
total += amount
return total
}
}
let incrementBy5 = makeIncrementer(amount: 5)
incrementBy5() // 5
incrementBy5() // 10
incrementBy5() // 15
// ── Trailing Closures ──
func perform(_ operation: (Int, Int) -> Int, a: Int, b: Int) -> Int {
return operation(a, b)
}
let result = perform(a: 3, b: 4) { $0 + $1 } // 7
// ── @escaping Closures ──
// Stored or executed after the function returns
func fetch(completion: @escaping (Result<Data, Error>) -> Void) {
DispatchQueue.global().async {
// ... async work ...
completion(.success(data))
}
}
// ── @autoclosure ──
// Wraps expression in a closure, deferred evaluation
func logIfTrue(_ condition: @autoclosure () -> Bool) {
if condition() { print("True!") }
}
logIfTrue(2 > 1) // condition evaluated only when called// ── map ──
let names = ["alice", "bob", "charlie"]
let uppercased = names.map { $0.uppercased() }
// ["ALICE", "BOB", "CHARLIE"]
let prices = [10.0, 20.0, 30.0]
let withTax = prices.map { $0 * 1.1 }
// ── filter ──
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let evens = numbers.filter { $0 % 2 == 0 }
// [2, 4, 6, 8, 10]
// ── reduce ──
let sum = numbers.reduce(0) { $0 + $1 }
let product = numbers.reduce(1) { $0 * $1 }
let sentence = ["Hello", "World"].reduce("") { $0 + " " + $1 }
// " Hello World"
// ── compactMap ──
let strings = ["1", "2", "three", "4", "five"]
let ints = strings.compactMap { Int($0) }
// [1, 2, 4]
// ── flatMap ──
let nested = [[1, 2], [3, 4], [5]]
let flat = nested.flatMap { $0 }
// [1, 2, 3, 4, 5]
let pairs = [(1, "a"), (2, "b"), (3, "c")]
let expanded = pairs.flatMap { [$0.0, $0.1] }
// [1, "a", 2, "b", 3, "c"]
// ── sorted / sort ──
let people = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]
let byName = people.sorted { $0.0 < $1.0 }
let byAge = people.sorted { $0.1 < $1.1 }
let byNameDesc = people.sorted(by: { $0.0 > $1.0 })
// ── contains, allSatisfy, first ──
numbers.contains { $0 > 5 } // true
numbers.allSatisfy { $0 > 0 } // true
numbers.first { $0 > 5 } // Optional(6)
numbers.last { $0 < 5 } // Optional(4)
numbers.firstIndex(of: 5) // Optional(4)
// ── Chaining ──
let result = numbers
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
.sorted(by: >)
.prefix(3)
// [100, 64, 36]| Feature | Named Function | Closure |
|---|---|---|
| Name | Has name | Anonymous or assigned to variable |
| Captures | Cannot capture | Captures surrounding context |
| Inlining | No | Can be inlined (optimizer) |
| Syntax | func name() { } | { } or { params in } |
// ── Protocols (like interfaces in other languages) ──
protocol Identifiable {
var id: String { get }
var name: String { get set }
func identify() -> String
}
protocol Describable {
var description: String { get }
}
// Protocol extension with default implementation
extension Describable {
var description: String { "A describable object" }
}
// Conforming to multiple protocols
struct User: Identifiable, Describable {
let id: String
var name: String
func identify() -> String { "User \(name) (\(id))" }
}
// Protocol composition
protocol Employee: Identifiable, Describable {
var role: String { get }
}
// ── Protocol as Type ──
func printDescription(_ item: Describable) {
print(item.description)
}
let items: [any Describable] = [user1, product1] // existential type
for item in items { printDescription(item) }
// ── Extensions ──
extension Int {
var squared: Int { self * self }
var isEven: Bool { self % 2 == 0 }
mutating func square() { self = self * self }
}
5.squared // 25
5.isEven // false
// Conditional extension (constrained)
extension Array where Element: Numeric {
func sum() -> Element { reduce(0, +) }
}
[1, 2, 3, 4, 5].sum() // 15// ── Generic Functions ──
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a; a = b; b = temp
}
func firstElement<T>(of array: [T]) -> T? {
array.first
}
// Multiple type parameters
func makePair<A, B>(_ a: A, _ b: B) -> (A, B) {
return (a, b)
}
// ── Generic Types ──
struct Queue<Element> {
private var elements: [Element] = []
mutating func enqueue(_ element: Element) { elements.append(element) }
mutating func dequeue() -> Element? { elements.isEmpty ? nil : elements.removeFirst() }
var front: Element? { elements.first }
var isEmpty: Bool { elements.isEmpty }
}
var stringQueue = Queue<String>()
stringQueue.enqueue("hello")
// ── Generic Constraints ──
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
array.firstIndex(of: value)
}
// Multiple constraints with where
func compare<T: Comparable, U: Comparable>(_ a: T, _ b: U) -> Bool {
// Not meaningful, but shows syntax
return true
}
// ── Associated Types ──
protocol Container {
associatedtype Item
var count: Int { get }
func get(_ index: Int) -> Item?
}
struct IntContainer: Container {
typealias Item = Int // or let Swift infer
var items: [Int] = []
var count: Int { items.count }
func get(_ index: Int) -> Int? { items.indices.contains(index) ? items[index] : nil }
}
// ── Opaque Types (some) vs Existentials (any) ──
// some: specific but hidden type (best for return types)
func makeIntContainer() -> some Container { IntContainer() }
// any: any type conforming to protocol (for stored properties)
var containers: [any Container] = []| Feature | some T | any T |
|---|---|---|
| Introduced | Swift 5.7 | Swift 5.7 |
| Type identity | One specific hidden type | Can be any conforming type |
| Performance | Static dispatch (fast) | Dynamic dispatch (existential) |
| Use for | Return types | Stored properties, collections |
import SwiftUI
// ── Basic View ──
struct ContentView: View {
var body: some View {
Text("Hello, SwiftUI!")
.font(.title)
.foregroundColor(.blue)
.padding()
}
}
// ── Modifiers ──
Text("Styled Text")
.font(.system(size: 20, weight: .bold))
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.blue)
.cornerRadius(10)
.shadow(radius: 5)
.frame(maxWidth: .infinity)
.padding()
// ── Stack Layouts ──
VStack(spacing: 16) { // vertical
Text("Title")
.font(.largeTitle)
Text("Subtitle")
.font(.subheadline)
.foregroundColor(.gray)
}
HStack(spacing: 8) { // horizontal
Image(systemName: "star.fill")
Text("Favorite")
}
ZStack { // layered
Image("background")
.resizable()
.aspectRatio(contentMode: .fill)
VStack { Text("Overlay Content") }
}
// ── Conditional Views ──
struct ProfileView: View {
@State private var isLoggedIn = false
var body: some View {
if isLoggedIn {
HomeView()
} else {
LoginView()
}
}
}import SwiftUI
// ── @State — local view state ──
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
.font(.largeTitle)
Button("Increment") { count += 1 }
.buttonStyle(.borderedProminent)
}
}
}
// ── @Binding — pass state to child views ──
struct ToggleRow: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Setting", isOn: $isOn)
}
}
// Parent provides the binding
struct SettingsView: View {
@State private var notificationsEnabled = true
var body: some View {
ToggleRow(isOn: $notificationsEnabled)
}
}
// ── @ObservedObject / @StateObject — reference type observation ──
class ViewModel: ObservableObject {
@Published var items: [String] = []
@Published var isLoading = false
func load() {
isLoading = true
// ... async work ...
items = ["Item 1", "Item 2"]
isLoading = false
}
}
struct ListView: View {
@StateObject private var vm = ViewModel()
var body: some View {
List(vm.items, id: \.self) { item in
Text(item)
}
.onAppear { vm.load() }
.overlay {
if vm.isLoading { ProgressView() }
}
}
}
// ── List ──
struct TodoListView: View {
@State private var todos = ["Buy groceries", "Walk dog"]
var body: some View {
NavigationView {
List {
ForEach(todos, id: \.self) { todo in
Text(todo)
}
.onDelete { todos.remove(atOffsets: $0) }
}
.navigationTitle("Todos")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Add") { todos.append("New todo") }
}
}
}
}
}| Wrapper | Ownership | Use Case |
|---|---|---|
| @State | Value type, view-owned | Simple local state |
| @Binding | Reference to parent @State | Child component state |
| @StateObject | ObservableObject, view-owned | Create & own a ViewModel |
| @ObservedObject | ObservableObject, parent-owned | Receive ViewModel from parent |
| @EnvironmentObject | ObservableObject, injected | Shared app-wide state |
| @Environment | System environment | Color scheme, locale, etc. |
// ── async / await (Swift 5.5+) ──
func fetchUser(id: Int) async throws -> User {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// async let — concurrent tasks
func loadDashboard() async throws -> Dashboard {
async let user = fetchUser(id: 1)
async let posts = fetchPosts(userId: 1)
async let notifications = fetchNotifications()
return try await Dashboard(
user: user,
posts: posts,
notifications: notifications
)
}
// Task — fire and forget
Task {
do {
let user = try await fetchUser(id: 1)
await MainActor.run { updateUserUI(user) }
} catch {
print("Error: \(error)")
}
}
// ── TaskGroup — structured concurrency ──
func fetchAllUsers(ids: [Int]) async throws -> [User] {
try await withThrowingTaskGroup(of: User.self) { group in
for id in ids {
group.addTask { try await fetchUser(id: id) }
}
var users: [User] = []
for try await user in group {
users.append(user)
}
return users
}
}
// ── Actors — thread-safe classes ──
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
self.balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) throws {
guard amount <= balance else { throw BankError.insufficientFunds }
balance -= amount
}
func getBalance() -> Double { balance }
}
// All access to actor is async (serialized)
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
let balance = await account.getBalance() // 1500// ── MainActor — UI thread ──
@MainActor
func updateUserUI(_ user: User) {
nameLabel.text = user.name
}
// Mark entire class as MainActor
@MainActor
class UserViewModel: ObservableObject {
@Published var user: User?
@Published var isLoading = false
func load() async {
isLoading = true
do {
user = try await fetchUser(id: 1)
} catch {
print("Failed: \(error)")
}
isLoading = false
}
}
// ── AsyncSequence ──
func streamNotifications() -> AsyncStream<Notification> {
AsyncStream { continuation in
// Set up stream...
continuation.onTermination = { @Sendable _ in
// Cleanup
}
}
}
for await notification in streamNotifications() {
print("New notification: \(notification)")
}
// ── Sendable — safe to pass across concurrency boundaries
struct Message: Sendable, Identifiable {
let id: UUID
let text: String
}
// ── withCheckedContinuation — bridge callback to async ──
func legacyFetch(completion: @escaping (Result<Data, Error>) -> Void) {
// Some callback-based API
}
func modernFetch() async throws -> Data {
try await withCheckedThrowingContinuation { continuation in
legacyFetch { result in
continuation.resume(with: result)
}
}
}
// ── Cancellation ──
func longRunningTask() async throws {
try Task.checkCancellation() // check if cancelled
for i in 0..<1000 {
try Task.sleep(nanoseconds: 1_000_000)
try Task.checkCancellation() // check periodically
}
}| Feature | GCD (old) | async/await (new) |
|---|---|---|
| Syntax | Closures + dispatch | async/await (linear) |
| Error handling | Difficult | try/catch (natural) |
| Cancellation | Manual | Built-in Task cancellation |
| Return value | Callback-based | Direct return |
| Safety | Data races possible | Compile-time checks |
Structs are value types (copied on assignment), have automatic memberwise initializers, no inheritance, and are preferred for data models. Classes are reference types (shared via pointers), support inheritance and deinitializers, and are used for shared mutable state and Objective-C interop. Default to struct; use class only when you need reference semantics or inheritance.
Optionals represent the absence of a value (nil). Swift uses them to eliminate null pointer exceptions — you cannot pass nil to a non-optional variable. This forces developers to explicitly handle missing values at compile time. Use if let/guard let for safe unwrapping, ?? for defaults, and ?. for safe chaining.
@State is view-local value-type state — owned by the view. @Binding creates a two-way reference to a parent's @State. @StateObject creates and owns an ObservableObject for the view. @ObservedObject observes an ObservableObject created elsewhere (passed from parent).
Copy-on-write is an optimization where value types (Array, String, Dictionary, Set) share underlying data until one is mutated. When you copy an array, both reference the same buffer. Only when you modify one does Swift create a separate copy. This makes value types as efficient as reference types for read-only access while maintaining value semantics safety.
Actors are reference types that provide thread-safe access to their mutable state. All access to an actor's properties and methods is serialized — only one task can access the actor at a time. This eliminates data races at compile time. Use actors for shared mutable state (caches, counters, databases). Unlike classes, actor isolation is enforced by the compiler.