Swift Cheatsheet

Syntax

Use this Swift reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Swift syntax essentials

ConstructExample
Constantlet name = "Ada"
Variablevar count = 0
Type annotationlet score: Int = 95
Tuplelet point = (x: 3, y: 4)
Type aliastypealias Grid = [[Int]]
String interpolation"score=\(score)"
Half-open range0..<n (excludes n)
Closed range1...n (includes n)
Comment// line or /* block */
print("Hello, Swift")

let greeting = "Hello"       // immutable, the default choice
var total = 0                // mutable
total += 1

let (x, y) = (3, 4)          // tuple destructuring
print("\(greeting): \(x + y)")

Top-level statements run directly in main.swift, script files, and online compilers. Prefer let. The compiler warns when a var is never mutated.

Numbers and conversions

let million = 1_000_000      // underscores for readability
let hexByte = 0xFF           // 255, also 0b1010 and 0o17
let half = 7 / 2             // 3, integer division
let rem = 7 % 2              // 1
let ratio = Double(7) / 2    // 3.5, conversions are always explicit
let parsed = Int("42")       // Int?, nil on bad input
let chopped = Int(3.9)       // 3, truncates toward zero

Int.max                      // 9223372036854775807 on 64-bit
abs(-5)
min(2, 9)
max(2, 9)
(2.5).rounded()              // 3.0 (.down, .up, .towardZero variants)

Swift never converts between numeric types implicitly. Mixed Int/Double arithmetic fails to compile until you convert one side.

if, guard, and ternary

let score = 87

if score >= 90 {
    print("A")
} else if score >= 80 {
    print("B")
} else {
    print("keep going")
}

let label = score >= 90 ? "A" : "below A"

func process(_ line: String?) {
    guard let line, !line.isEmpty else { return }   // early exit
    print(line)                                     // binding still in scope
}

guard must exit its scope in the else branch (return, throw, break, continue, or fatalError). Bindings made in the condition remain visible after it.

Loops

for i in 0..<5 { print(i) }                       // 0 1 2 3 4
for i in stride(from: 10, through: 0, by: -2) { print(i) }
for (i, value) in ["a", "b"].enumerated() { print(i, value) }
for char in "swift" { print(char) }

var n = 100
while n > 1 { n /= 2 }

repeat { n += 3 } while n < 10                    // body runs at least once

Labeled loops break out of nesting:

outer: for row in grid {
    for cell in row {
        if cell == target { break outer }
    }
}

switch and pattern matching

let status = 404

switch status {
case 200: print("ok")
case 301, 302: print("redirect")
case 400..<500: print("client error")
case let code where code >= 500: print("server error \(code)")
default: print("other")
}

switch is exhaustive: cover every possible value or add default. There is no implicit fallthrough, so no break after each case (opt in with the fallthrough keyword).

Tuples and one-off patterns:

switch (x, y) {
case (0, 0): print("origin")
case (_, 0): print("on the x axis")
case let (a, b) where a == b: print("diagonal")
default: print("elsewhere")
}

let digit = 7
if case 1...9 = digit { print("single digit") }