All cheatsheets

Cheatsheets

Swift

Optionals, structs vs classes, enums with associated values, protocols, and closures.

Test yourself

64 entries

Bindings & type inference7

let x = 5

Immutable constant — x cannot be reassigned (default choice).

var y = 5

Mutable variable — y can be reassigned.

let pi: Double = 3.14

Explicit type annotation — needed when inference can't decide or you want a wider type.

let (a, b) = (1, 2)

Tuple destructuring in one binding.

let big = 1_000_000

Underscores group digits in numeric literals (ignored).

typealias Handler = (Int) -> Void

Alias a type for readability — no new type created.

let s = "\(name) is \(age)"

String interpolation with \(expr).

Optionals6

var name: String?

Optional — a value that may be a String or nil. Swift's answer to null.

if let name = name { ... }

Optional binding — runs the block only if non-nil, with name unwrapped inside.

guard let name = name else { return }

Early-exit unwrap — bind for the REST of the scope, or bail out.

let port = config["port"] ?? 8080

Nil-coalescing — provide a default when the optional is nil.

let n = str!

Force-unwrap — CRASHES if nil. Use only when nil is a programmer error.

var x: Int!

Implicitly-unwrapped optional — auto-unwraps on use (mainly for @IBOutlet / late init).

Structs vs classes (value vs reference)8

struct Point { var x, y: Double }

Value type — copied on assignment/passing. Default building block in Swift.

class Person { var name: String }

Reference type — variables share ONE instance; copying copies the reference.

mutating func moveBy(dx: Double) { x += dx }

Methods that change a struct's stored properties must be marked mutating.

let copy = original // value type copies

Value semantics — assigning a struct/enum/tuple makes an independent copy.

final class Foo { }

final forbids subclassing/overriding — enables devirtualization (faster).

if a === b { }

=== / !== compare class instance identity (same object), not value equality.

deinit { cleanup() }

Class-only destructor — runs when the last reference is released (ARC).

func bump(_ x: inout Int) { x += 1 }

inout passes a value param by reference so the function can mutate the caller's variable.

Enums & pattern matching6

enum Direction { case north, south, east, west }

A finite set of named cases — exhaustively checkable by the compiler.

enum Result { case success(Int); case failure(Error) }

Associated values — each case can carry its own typed payload.

enum Planet: Int { case mercury = 1, venus, earth }

Raw values — back each case with a literal (Int/String/etc.), with init?(rawValue:).

if case .loaded(let text) = state { ... }

if case — match a single enum case and bind its payload without a full switch.

enum E: CaseIterable { ... }; E.allCases

CaseIterable synthesizes allCases — iterate every case.

indirect enum Tree { case leaf(Int); case node(Tree, Tree) }

indirect allows recursive enums (boxed).

Protocols & extensions8

protocol Shape { var area: Double { get } }

A contract of requirements types can conform to — Swift's interface mechanism.

extension Shape { func describe() -> String { ... } }

Protocol extension — give EVERY conformer a default implementation/behaviour.

func paint(_ s: some Shape)

some (opaque type) vs any (existential) — prefer some for one concrete-but-hidden type.

protocol Container { associatedtype Item }

associatedtype — a protocol-level placeholder filled in by each conformer.

extension Int { var squared: Int { self * self } }

Extend any existing type (even stdlib) with new methods/computed props.

protocol Drawable: AnyObject { }

AnyObject constraint restricts conformance to classes (needed for weak refs).

func first<T>(_ a: [T]) -> T?

Generics — write one algorithm that works for any type, type-safely.

func sum<S: Sequence>(_ s: S) -> Int where S.Element == Int

where clause — add constraints on generic/associated types.

Closures6

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

Closure — a self-contained, first-class block of code you can store and pass.

items.map { $0 * 2 }

Trailing closure — a final closure argument moves outside the parentheses.

{ [weak self] in self?.update() }

Capture list [weak self] — break the retain cycle when a closure outlives its owner.

func run(_ work: @escaping () -> Void)

@escaping marks a closure param that is stored / called after the function returns.

let inc = makeCounter()

Closures capture by reference — returned closures keep their captured state alive.

nums.sorted { $0 > $1 }

Pass a closure to customise behaviour (sort descending here).

Collections & functional APIs7

var a = [1, 2, 3]; a.append(4)

Array — ordered, indexed, value-type (copy-on-write) sequence.

var d = ["a": 1, "b": 2]

Dictionary — unordered key→value map; subscript returns an Optional.

let s: Set = [1, 2, 2, 3] // {1, 2, 3}

Set — unordered collection of unique Hashable elements with fast membership.

nums.map { $0 * 2 }.filter { $0 > 4 }.reduce(0, +)

map / filter / reduce — transform, select, and fold a sequence functionally.

for (i, v) in arr.enumerated() { }

enumerated() yields (index, element) pairs while iterating.

let names = people.sorted { $0.age < $1.age }

sorted(by:) returns a new sorted array (non-mutating).

Dictionary(grouping: words, by: \.first)

Group a sequence into a [Key: [Element]] dictionary.

Error handling6

enum NetError: Error { case offline, badStatus(Int) }

Errors are any type conforming to the Error protocol — usually an enum.

func parse() throws -> Int

throws — declares a function can fail; callers must use try.

do { try foo() } catch { print(error) }

do/try/catch — run throwing code and handle errors, matching by pattern.

let x = try? foo()

try? — turn a thrown error into nil (optional result); try! traps on error.

defer { file.close() }

defer schedules cleanup that runs when the scope exits (even on throw/return).

Result<Int, NetError>

Result enum — capture success/failure as a value (great for async callbacks).

Properties & control flow10

var area: Double { width * height }

Computed property — runs code on every access; stores nothing.

var temp: Double { didSet { log(temp) } }

Property observers willSet / didSet run on every change to a stored property.

lazy var heavy = expensiveBuild()

lazy var — stored, computed once on first access (must be var).

static let shared = Manager()

Type property — one value shared by the type itself (e.g. a singleton).

for i in 0..<n { }

Ranges: 0..<n (half-open, excludes n) and 0...n (closed, includes n).

switch x { case 1...5: ...; default: ... }

switch — exhaustive, pattern-matching, no implicit fallthrough.

let label = condition ? "on" : "off"

Ternary conditional — pick one of two values inline.

let json = user?.address?.city

Optional chaining — call/access through optionals; the whole expression is optional.

people.sorted(using: KeyPathComparator(\.age))

Key paths (\.prop) reference a property as a value — for sorting/mapping.

assert(x > 0, "must be positive")

assert (debug-only) / precondition (always) document and enforce invariants.