Swift Cheatsheet

Types, optionals, closures, protocols, structs vs classes, concurrency & SwiftUI basics

Language
Contents
🍎

Basics & Types

// Variables & constants
var name = "Alice"       // mutable
let age = 30              // immutable (prefer let)

// Type annotations
let x: Int = 42
let pi: Double = 3.14
let flag: Bool = true
let ch: Character = "A"

// String interpolation
let msg = "Hello \(name), you are \(age)"

// Multi-line strings
let text = """
    This is a
    multi-line string
    """

// Type conversion
let intVal = Int("42")        // Optional Int?
let dblVal = Double(age)      // 30.0
let strVal = String(age)      // "30"

// Tuples
let point = (x: 10, y: 20)
point.x   // 10
let (a, b) = point  // destructure
❓

Optionals

Swift's optionals handle the absence of a value safely β€” no null pointer exceptions.

var email: String? = nil   // optional String
email = "alice@example.com"

// Optional binding (safe unwrap)
if let e = email {
    print("Email: \(e)")
}

// guard let (early exit)
guard let e = email else {
    print("No email")
    return
}
// e is available here

// Nil coalescing
let display = email ?? "No email"

// Optional chaining
let count = email?.count  // Int? β€” nil if email is nil

// Force unwrap (avoid if possible)
let forced = email!  // crashes if nil
πŸ“¦

Collections

// Array
var nums: [Int] = [1, 2, 3]
nums.append(4)
nums.insert(0, at: 0)
nums.remove(at: 0)
nums.contains(3)         // true
nums.sorted()              // returns new sorted array
nums.filter { $0 > 2 }     // [3, 4]
nums.map { $0 * 2 }        // [2, 4, 6, 8]
nums.reduce(0, +)          // 10
nums.compactMap { Int($0) } // filter nil from optionals
nums.flatMap { [$0, $0*2] }

// Dictionary
var scores: [String: Int] = ["Alice": 95, "Bob": 87]
scores["Alice"]             // Optional Int?
scores["Charlie"] = 92     // add/update
scores.keys / scores.values
for (name, score) in scores { ... }

// Set
var tags: Set<String> = ["swift", "ios"]
tags.insert("macos")
tags.contains("swift")
tags.intersection(otherSet)
tags.union(otherSet)
πŸ”€

Control Flow

// if/else
if age >= 18 {
    print("adult")
} else if age >= 13 {
    print("teen")
} else {
    print("child")
}

// switch (exhaustive, no fall-through)
switch role {
case "admin":
    print("full access")
case "user", "member":  // multiple values
    print("limited")
case let r where r.hasPrefix("super"):
    print("super role: \(r)")
default:
    print("guest")
}

// for-in
for i in 0..<5 { }      // 0,1,2,3,4
for i in 1...5 { }      // 1,2,3,4,5
for (i, val) in arr.enumerated() { }
for _ in 0..<3 { }      // ignore counter

// while
while x < 10 { x += 1 }
repeat { x += 1 } while x < 10  // do-while
πŸ”§

Functions & Closures

// Function with labels
func greet(person name: String, from city: String = "Unknown") -> String {
    return "Hello \(name) from \(city)"
}
greet(person: "Alice", from: "NYC")

// Multiple return (tuple)
func minMax(_ arr: [Int]) -> (min: Int, max: Int) {
    return (arr.min()!, arr.max()!)
}

// Closures
let add = { (a: Int, b: Int) -> Int in
    return a + b
}

// Shorthand closure syntax
nums.sorted { $0 < $1 }
nums.sorted(by: <)

// Trailing closure
nums.filter { $0 > 3 }
    .map { $0 * 2 }
    .forEach { print($0) }

// @escaping (closure outlives function)
func fetch(completion: @escaping (String) -> Void) { }
πŸ—οΈ

Structs, Classes & Enums

// Struct (value type β€” copied)
struct Point {
    var x: Double
    var y: Double

    func distance(to other: Point) -> Double {
        sqrt(pow(x - other.x, 2) + pow(y - other.y, 2))
    }

    mutating func translate(dx: Double, dy: Double) {
        x += dx; y += dy
    }
}

// Class (reference type β€” shared)
class Vehicle {
    var speed: Double = 0
    init(speed: Double) { self.speed = speed }
    deinit { print("deallocated") }
}

class Car: Vehicle {
    var brand: String
    init(brand: String, speed: Double) {
        self.brand = brand
        super.init(speed: speed)
    }
}

// Enum with associated values
enum Result<T> {
    case success(T)
    case failure(String)
}

enum Direction: String, CaseIterable {
    case north, south, east, west
}
πŸ’‘ Struct vs Class: Prefer structs. Use classes only when you need reference semantics, inheritance, or deinit.
πŸ“

Protocols & Extensions

// Protocol (like interface/trait)
protocol Drawable {
    func draw()
    var area: Double { get }
}

struct Circle: Drawable {
    var radius: Double
    var area: Double { .pi * radius * radius }
    func draw() { print("Drawing circle r=\(radius)") }
}

// Extension (add functionality to existing types)
extension String {
    var isEmail: Bool {
        contains("@") && contains(".")
    }
}
"a@b.com".isEmail  // true

// Protocol extension (default implementation)
extension Drawable {
    func description() -> String { "Area: \(area)" }
}
⚠️

Error Handling

enum AppError: Error {
    case notFound
    case unauthorized(String)
    case serverError(code: Int)
}

func fetchUser(id: Int) throws -> User {
    guard id > 0 else { throw AppError.notFound }
    return User(name: "Alice")
}

// do-try-catch
do {
    let user = try fetchUser(id: 1)
} catch AppError.notFound {
    print("Not found")
} catch {
    print("Error: \(error)")
}

// try? (returns optional), try! (force)
let user = try? fetchUser(id: 1)  // User?
⚑

Concurrency (async/await)

// Async function
func fetchData(url: URL) async throws -> Data {
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}

// Call async function
Task {
    let data = try await fetchData(url: myURL)
}

// Structured concurrency
async let users = fetchUsers()
async let posts = fetchPosts()
let (u, p) = try await (users, posts)  // parallel

// Actor (thread-safe shared state)
actor Counter {
    private var count = 0
    func increment() { count += 1 }
    func getCount() -> Int { count }
}
πŸ“±

SwiftUI Basics

import SwiftUI

struct ContentView: View {
    @State private var count = 0
    @State private var name = ""

    var body: some View {
        VStack(spacing: 20) {
            Text("Count: \(count)")
                .font(.title)
                .foregroundColor(.blue)

            Button("Increment") { count += 1 }
                .buttonStyle(.borderedProminent)

            TextField("Enter name", text: $name)
                .textFieldStyle(.roundedBorder)

            List {
                ForEach(items) { item in
                    Text(item.name)
                }
            }
        }
        .padding()
        .onAppear { loadData() }
    }
}

// Property wrappers
// @State β€” local mutable state
// @Binding β€” two-way binding to parent
// @ObservedObject β€” external observable
// @EnvironmentObject β€” shared app state
// @Published β€” auto-notify on change