Jump to section
Swift Cheatsheet
A practical Swift guide covering syntax, optionals, protocols, SwiftUI, concurrency, collections, and iOS development workflows.
What is Swift?
Swift is Apple's programming language for building iOS, macOS, and watchOS apps. It's fast, safe by design, and honestly a lot more readable than Objective-C — which is what it replaced.
where swift is used
- The primary language for all Apple platform development.
- Replaced Objective-C as the standard — all new Apple APIs are Swift-first.
- Same language, same concepts — runs on Apple Watch and Apple TV.
- SwiftUI makes sharing UI code across platforms easier.
- Vapor is the main Swift web framework.
- Less common than iOS but growing — same language, different target.
your first swift program
Swift
// no class needed — just start writing
print("Hello, World!")
// print with string interpolation
let name = "Alice"
print("Hello, \(name)!")
// Hello, Alice!
// print without newline
print("Hello ", terminator: "")
print("World")
// Hello Worldcomments and special markers
Swift
// single-line comment
/*
multi-line comment
can span many lines
*/
/// documentation comment
/// shown in Xcode's Quick Help panel
/// - Parameter name: the user's name
/// - Returns: a greeting string
func greet(name: String) -> String {
return "Hello, \(name)!"
}
// MARK: - View Settings
// appears as a divider in Xcode jump bar
// TODO: update this logic later
// shown as a reminder in Xcode
// FIXME: crashes on empty input
// shown as a bug reminder in XcodeVariables & Data Types
Swift has two kinds of storage: constants and variables. The rule is simple — use let by default. Switch to var only when the value genuinely needs to change.
let and var
Swift
// let: constant — cannot be changed
let pi = 3.14159
let appName = "MyApp"
// pi = 3 ← compile error
// var: variable — can be changed
var score = 0
score = 10 // fine
score += 5 // fine
// Swift infers the type automatically
let city = "Colombo" // String
let age = 25 // Int
let price = 9.99 // Double
let isReady = true // Boolbasic data types
Swift
// explicit type annotations
let count: Int = 42
let price: Double = 19.99
let ratio: Float = 0.5
let flag: Bool = true
let name: String = "Alice"
let initial: Character = "A"
// typealias — give a type a new name
typealias UserID = Int
let myID: UserID = 1001
// type conversion — always explicit
let intVal = 10
let dblVal = Double(intVal) // 10.0
let strVal = String(intVal) // "10"
let backInt = Int("42") ?? 0 // 42tuples — group values without a class
Swift
// basic tuple
let player = ("Alice", 5, 150)
player.0 // "Alice"
player.1 // 5
player.2 // 150
// named tuple — easier to read
let user = (name: "Alice", age: 28, score: 150)
user.name // "Alice"
user.age // 28
user.score // 150
// decompose into variables
let (userName, userAge, userScore) = user
print(userName) // Alice
// ignore parts you don't need
let (justName, _, _) = user
// return multiple values from a function
func minMax(arr: [Int]) -> (min: Int, max: Int) {
return (arr.min()!, arr.max()!)
}
let result = minMax(arr: [3, 1, 9, 2])
result.min // 1
result.max // 9Strings
Swift strings are full Unicode by default. String interpolation with \() is cleaner than concatenation and works with any value — not just text.
string interpolation and multiline
Swift
let name = "Alice"
let score = 95
let pi = 3.14159
// interpolation — clean and readable
print("Hello, \(name)!")
print("Score: \(score * 2)")
print("Pi is about \(pi)")
// expression inside interpolation
print("Next year: \(2024 + 1)")
// concatenation with +
let full = "Hello, " + name + "!"
// multiline string — triple quotes
let message = """
Dear \(name),
Your score is \(score).
Well done!
"""
// leading spaces trimmed from each linecommon string methods
Swift
var s = " Hello, Swift! "
// length and checks
s.count // 17
s.isEmpty // false
"".isEmpty // true
let clean = s.trimmingCharacters(
in: .whitespaces
)
// "Hello, Swift!"
// case
clean.uppercased() // "HELLO, SWIFT!"
clean.lowercased() // "hello, swift!"
// search
clean.contains("Swift") // true
clean.hasPrefix("Hello") // true
clean.hasSuffix("!") // true
// modify (returns new String — Strings are value types)
clean.replacingOccurrences(
of: "Swift",
with: "World"
)
// "Hello, World!"
// split
"a,b,c".components(
separatedBy: ","
)
// ["a", "b", "c"]
// starts and ends
clean.first // Optional("H")
clean.last // Optional("!")Operators
Most operators work exactly as you'd expect. The ones worth paying attention to in Swift are the range operators and nil coalescing — they show up constantly in real code.
arithmetic, comparison, and logical
Swift
// arithmetic
5 + 3 // 8
5 - 3 // 2
5 * 3 // 15
5 / 2 // 2 (integer division — decimal dropped)
5 % 2 // 1 (remainder)
5.0 / 2 // 2.5 (Double division)
// compound assignment
var x = 10
x += 5 // 15
x -= 3 // 12
x *= 2 // 24
x /= 4 // 6
// comparison — returns Bool
5 == 5 // true
5 != 3 // true
5 > 3 // true
5 < 3 // false
5 >= 5 // true
5 <= 4 // false
// logical
true && false // false (AND)
true || false // true (OR)
!true // false (NOT)
// identity — checks same object in memory
// (for classes only)
let a = SomeClass()
let b = a
a === b // true (same instance)
a !== b // falserange operators and nil coalescing
Swift
// closed range: includes both ends
for i in 1...5 {
print(i) // 1 2 3 4 5
}
// half-open range: excludes upper end
for i in 1..<5 {
print(i) // 1 2 3 4
}
// one-sided range: useful for array slicing
let names = ["Alice", "Bob", "Carol", "Dave"]
names[2...] // ["Carol", "Dave"]
names[...1] // ["Alice", "Bob"]
names[..<2] // ["Alice", "Bob"]
// nil coalescing: ?? provides a fallback
let input: String? = nil
let value = input ?? "default"
// "default"
// chain ?? for multiple fallbacks
let a: String? = nil
let b: String? = nil
let c = "found"
let result = a ?? b ?? c // "found"Control Flow
Swift's switch is one of the most powerful in any language — it matches ranges, tuples, and types without fall-through. And guard is worth learning early: it makes code much easier to follow.
if, else if, else
Swift
let score = 75
if score >= 90 {
print("A")
} else if score >= 75 {
print("B")
} else if score >= 60 {
print("C")
} else {
print("F")
}
// ternary operator
let label = score >= 50 ? "Pass" : "Fail"
// if as an expression (Swift 5.9+)
let grade = if score >= 90 { "A" }
else if score >= 75 { "B" }
else { "F" }switch — pattern matching
Swift
let score = 82
// match ranges
switch score {
case 90...100:
print("A")
case 75..<90:
print("B")
case 60..<75:
print("C")
default:
print("F")
}
// match multiple values
let day = "Sat"
switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
print("Weekday")
case "Sat", "Sun":
print("Weekend")
default:
print("Unknown")
}
// match with where clause
let point = (2, -3)
switch point {
case let (x, y) where x == y:
print("On diagonal")
case let (x, y) where x > 0 && y > 0:
print("First quadrant")
case let (x, _) where x < 0:
print("Left side")
default:
print("Somewhere else")
}guard — early exit
Swift
// without guard — nested and hard to read
func processUser(name: String?) {
if let name = name {
if name.count > 2 {
print("Hello, \(name)")
// real logic buried in nesting
}
}
}
// with guard — flat and readable
func processUser(name: String?) {
guard let name = name else {
print("Name is missing")
return // must exit here
}
// name is available here as non-optional
guard name.count > 2 else {
print("Name too short")
return
}
print("Hello, \(name)")
// real logic at the top level
}
// guard with multiple conditions
func login(user: String?, pass: String?) {
guard
let user = user,
let pass = pass,
!user.isEmpty,
pass.count >= 8
else {
print("Invalid credentials")
return
}
print("Welcome, \(user)")
}Loops
for-in is the workhorse of Swift loops. It works with ranges, arrays, dictionaries, and anything that conforms to Sequence — which is most things you'll loop over.
for-in loops
Swift
// range
for i in 1...5 {
print(i) // 1 2 3 4 5
}
// ignore the loop variable
for _ in 1...3 {
print("hello") // prints 3 times
}
// stride — custom step
for i in stride(from: 0, to: 10, by: 2) {
print(i) // 0 2 4 6 8
}
// count down
for i in stride(from: 5, through: 1, by: -1) {
print(i) // 5 4 3 2 1
}
// iterate array
let fruits = ["Apple", "Mango", "Grape"]
for fruit in fruits {
print(fruit)
}
// with index using enumerated
for (index, fruit) in fruits.enumerated() {
print("\(index): \(fruit)")
}
// filter during loop with where
for fruit in fruits where fruit.count > 5 {
print(fruit) // "Mango", "Grape" skipped
}
// forEach — closure style
fruits.forEach { fruit in
print(fruit)
}while, repeat-while, break, continue
Swift
// while
var i = 0
while i < 5 {
print(i)
i += 1
}
// repeat-while — runs at least once
var j = 10
repeat {
print(j) // prints 10
j += 1
} while j < 5
// break — exit loop immediately
for i in 1...10 {
if i == 5 { break }
print(i) // 1 2 3 4
}
// continue — skip this iteration
for i in 1...5 {
if i == 3 { continue }
print(i) // 1 2 4 5
}
// labelled loops — break outer loop
outer: for i in 1...3 {
for j in 1...3 {
if i == 2 && j == 2 {
break outer
}
print("\(i),\(j)")
}
}Optionals
Optionals are one of Swift's best features. Every value is non-nil by default — you have to explicitly say a variable can be nil by adding ?. That one rule eliminates an entire category of crashes.
what optionals are
Swift
// non-optional: cannot be nil
var name: String = "Alice"
// name = nil ← compile error
// optional: might be nil
var nickname: String? = nil
var city: String? = "Colombo"
// you cannot use an optional directly
// print(nickname.count) ← compile error
// must unwrap first
// optional values wrap in Optional()
print(city) // Optional("Colombo")
print(nickname) // nilif let, guard let, and nil coalescing
Swift
var username: String? = "Alice"
// if let — value lives inside the block
if let name = username {
print("Hello, \(name)")
} else {
print("No name provided")
}
// shorthand (Swift 5.7+) — same name
if let username {
print("Hello, \(username)")
}
// guard let — value lives AFTER the guard
func greet(username: String?) {
guard let name = username else {
print("No name")
return
}
// name available here
print("Hello, \(name)")
}
// nil coalescing ?? — fallback value
let display = username ?? "Guest"
print(display) // "Alice"
let noName: String? = nil
let fallback = noName ?? "Guest"
print(fallback) // "Guest"optional chaining and force unwrap
Swift
// optional chaining — stops at nil, returns nil
struct Address {
var city: String?
}
struct Person {
var address: Address?
}
let person: Person? = Person(
address: Address(city: "Colombo")
)
// each ? propagates nil if anything is nil
let city = person?.address?.city
// Optional("Colombo")
// chain with methods
let upper = person?.address?.city?.uppercased()
// Optional("COLOMBO")
// if any link is nil, whole thing returns nil
let nobody: Person? = nil
nobody?.address?.city // nil (no crash)
// force unwrap — use with caution
let forced = person!.address!.city!
// "Colombo" — crashes if any is nil
// safe pattern: check first
if let city = person?.address?.city {
print(city.uppercased())
}Every ! in your code is a potential crash. If you see yourself using ! often, use if let or guard let instead.
Functions
Swift functions have a feature most languages don't — argument labels. The label is what the caller writes, the parameter name is what you use inside. It makes function calls read almost like English.
defining and calling functions
Swift
// no return value
func greet() {
print("Hello!")
}
// with parameter and return type
func add(a: Int, b: Int) -> Int {
return a + b
}
// single expression — implicit return
func square(n: Int) -> Int {
n * n
}
// multiple return values with tuple
func minMax(nums: [Int]) -> (min: Int, max: Int) {
return (nums.min()!, nums.max()!)
}
// call the functions
greet() // Hello!
add(a: 3, b: 4) // 7
square(n: 5) // 25
let r = minMax(nums: [1, 9, 3, 7])
r.min // 1
r.max // 9argument labels and default parameters
Swift
// argument label vs parameter name
// func name(label paramName: Type)
func greet(to name: String) {
print("Hello, \(name)!")
// 'name' used inside
}
greet(to: "Alice") // 'to' used by caller
// suppress label with _
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
add(3, 4) // no labels needed
// default parameters
func createUser(
name: String,
role: String = "user",
isActive: Bool = true
) {
print("\(name) | \(role) | \(isActive)")
}
createUser(name: "Alice")
// Alice | user | true
createUser(name: "Bob", role: "admin")
// Bob | admin | true
createUser(name: "Carol", isActive: false)
// Carol | user | falseclosures — basics and trailing syntax
Swift
// full closure syntax
let add = { (a: Int, b: Int) -> Int in
return a + b
}
add(3, 4) // 7
// type inferred — shorter
let double = { (n: Int) -> Int in n * 2 }
// shorthand argument names
let triple = { $0 * 3 }
triple(5) // 15
// passing a closure as an argument
func operate(
_ a: Int,
_ b: Int,
using op: (Int, Int) -> Int
) -> Int {
return op(a, b)
}
// inline closure
operate(3, 4, using: { $0 + $1 }) // 7
// trailing closure — last arg goes outside ()
operate(3, 4) { $0 * $1 } // 12
// trailing closure with named params
[1, 2, 3].map { number in
number * 10
}
// [10, 20, 30]Collections
Swift has three main collection types. Array for ordered lists, Dictionary for key-value pairs, and Set for unique unordered values. All three are value types — assigning one copies it.
Array
Swift
// create
var fruits = ["Apple", "Mango", "Grape"]
var nums = [Int]() // empty array
var zeros = Array(repeating: 0, count: 5)
// access
fruits[0] // "Apple"
fruits.first // Optional("Apple")
fruits.last // Optional("Grape")
fruits.count // 3
fruits.isEmpty // false
// modify
fruits.append("Kiwi")
fruits.insert("Berry", at: 1)
fruits.remove(at: 0)
fruits.removeFirst()
fruits.removeLast()
fruits[0] = "Lemon" // update
// search
fruits.contains("Mango") // true
fruits.firstIndex(of: "Grape") // Optional(1)
// sort
fruits.sort() // in-place (var only)
let sorted = fruits.sorted() // new array
// iterate
for fruit in fruits { print(fruit) }Dictionary and Set
Swift
// ── Dictionary ──────────────────────────────
var scores: [String: Int] = [
"Alice": 90,
"Bob": 85
]
// access — always returns Optional
scores["Alice"] // Optional(90)
scores["Alice"] ?? 0 // 90
// add and update
scores["Carol"] = 92
scores["Alice"] = 95 // update
// remove
scores["Bob"] = nil // removes Bob
scores.removeValue(forKey: "Bob")
// check
scores.keys.contains("Alice") // true
scores.count // 2
// iterate
for (name, score) in scores {
print("\(name): \(score)")
}
// ── Set ──────────────────────────────────
var tags: Set = ["swift", "ios", "swift"]
// {"swift", "ios"} — duplicates removed
tags.insert("xcode")
tags.remove("ios")
tags.contains("swift") // true
tags.count // 2
// 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.subtracting(b) // {1,2}filter, map, reduce, and compactMap
Swift
let nums = [1, 2, 3, 4, 5, 6]
// filter: keep only even numbers
nums.filter { $0 % 2 == 0 }
// [2, 4, 6]
// map: multiply each by 10
nums.map { $0 * 10 }
// [10, 20, 30, 40, 50, 60]
// reduce: sum all values
// 0 is the starting value
nums.reduce(0) { $0 + $1 } // 21
// shorthand:
nums.reduce(0, +) // 21
// compactMap: map and remove nils
let strings = ["1", "two", "3", "four"]
strings.compactMap { Int($0) }
// [1, 3] — "two" and "four" returned nil
// chain operations
let result = nums
.filter { $0 % 2 == 0 } // [2, 4, 6]
.map { $0 * $0 } // [4, 16, 36]
.reduce(0, +) // 56
// sorted with custom comparator
let names = ["Carol", "Alice", "Bob"]
names.sorted { $0 < $1 } // A→Z
names.sorted { $0 > $1 } // Z→A
names.sorted { $0.count < $1.count } // by lengthStructs & Classes
Swift has both structs and classes — and unlike most languages, structs are the preferred choice. The key difference is that structs are value types and classes are reference types. That distinction matters a lot.
struct — value type
Swift
struct Person {
var name: String
var age: Int
// memberwise init is generated automatically
// no need to write it unless you want custom logic
// method that modifies a property
// must be marked 'mutating'
mutating func birthday() {
age += 1
}
// computed property
var greeting: String {
"Hi, I'm \(name)"
}
}
var alice = Person(name: "Alice", age: 28)
var copy = alice // makes a full copy
copy.name = "Carol" // only copy is changed
print(alice.name) // "Alice" — unchanged
print(copy.name) // "Carol"
alice.birthday()
print(alice.age) // 29class — reference type
Swift
class Animal {
var name: String
// class requires explicit init
init(name: String) {
self.name = name
}
func speak() {
print("\(name) makes a sound")
}
}
// inheritance
class Dog: Animal {
var breed: String
init(name: String, breed: String) {
self.breed = breed
super.init(name: name)
}
override func speak() {
print("\(name) barks")
}
}
let dog1 = Dog(name: "Rex", breed: "Lab")
let dog2 = dog1 // same object, NOT a copy
dog2.name = "Max"
print(dog1.name) // "Max" — both changed!
// prevent subclassing
final class Singleton {
static let shared = Singleton()
private init() {}
}struct vs class — when to use which
Swift
// ✅ struct — for data models
struct Point {
var x: Double
var y: Double
}
struct User {
let id: Int
var name: String
var email: String
}
// ✅ class — for shared services
class NetworkManager {
static let shared = NetworkManager()
var baseURL = "https://api.example.com"
func fetch(path: String) {
// network call
}
}
// use the shared instance anywhere
NetworkManager.shared.fetch(path: "/users")Enums
Swift enums are far more capable than in most languages. They can carry associated values, have methods, and conform to protocols. Once you start using them properly, you'll reach for them constantly.
basic enums and raw values
Swift
// basic enum
enum Direction {
case north
case south
case east
case west
}
let dir = Direction.north
// String raw values
// each case's rawValue is its name by default
enum Status: String {
case active = "active"
case inactive = "inactive"
case pending = "pending"
}
let s = Status.active
s.rawValue // "active"
// create from raw value — returns Optional
let fromRaw = Status(rawValue: "pending")
// Optional(Status.pending)
// Int raw values — auto-increments from 0
enum Priority: Int {
case low // 0
case medium // 1
case high // 2
}
Priority.high.rawValue // 2
// CaseIterable — loop over all cases
enum Day: String, CaseIterable {
case mon, tue, wed, thu, fri, sat, sun
}
for day in Day.allCases {
print(day.rawValue)
}associated values and switch
Swift
// associated values
enum NetworkResult {
case loading
case success(data: String)
case failure(error: String, code: Int)
}
let result = NetworkResult.success(
data: "User data loaded"
)
// switch to extract associated values
switch result {
case .loading:
print("Loading...")
case .success(let data):
print("Got: \(data)")
case .failure(let error, let code):
print("Error \(code): \(error)")
}
// if case — check one specific case
if case .success(let data) = result {
print("Success: \(data)")
}
// enum with methods
enum Coin {
case penny, nickel, dime, quarter
var value: Int {
switch self {
case .penny: return 1
case .nickel: return 5
case .dime: return 10
case .quarter: return 25
}
}
}
Coin.quarter.value // 25Protocols & Extensions
Protocols define what something can do — without saying how. Extensions let you add new capabilities to any existing type, even ones you didn't write. Together they're the foundation of Swift's design philosophy.
protocols — define a contract
Swift
// define a protocol
protocol Greetable {
var name: String { get }
func greet() -> String
}
// protocol with default implementation
protocol Describable {
var description: String { get }
func describe()
}
extension Describable {
func describe() {
// default — conforming types get this free
print(description)
}
}
// conform to a protocol
struct User: Greetable, Describable {
var name: String
func greet() -> String {
"Hello, I'm \(name)"
}
var description: String {
"User: \(name)"
}
// describe() comes from the extension — free
}
let u = User(name: "Alice")
u.greet() // "Hello, I'm Alice"
u.describe() // "User: Alice"
// built-in protocols worth knowing
struct Point: Equatable, Hashable, Codable {
var x: Double
var y: Double
// compiler generates == and hash automatically
}extensions — add to any type
Swift
// add a method to an existing type
extension String {
func shout() -> String {
return self.uppercased() + "!!!"
}
var wordCount: Int {
self.split(separator: " ").count
}
var isPalindrome: Bool {
self == String(self.reversed())
}
}
"hello".shout() // "HELLO!!!"
"hello world".wordCount // 2
"racecar".isPalindrome // true
// extend Int
extension Int {
var isEven: Bool { self % 2 == 0 }
var doubled: Int { self * 2 }
func times(_ action: () -> Void) {
for _ in 0..<self { action() }
}
}
4.isEven // true
5.doubled // 10
3.times { print("Hello") } // prints 3 times
// add protocol conformance via extension
extension User: CustomStringConvertible {
var description: String {
"User(\(name))"
}
}Error Handling
Swift error handling is explicit — functions that can fail must say so with throws. That said, you have options for how to deal with errors. try?, Result, and try! all have their place.
throws, try, and do-catch
Swift
// define custom errors
enum LoginError: Error {
case emptyUsername
case wrongPassword
case accountLocked(reason: String)
}
// function that can throw
func login(user: String, pass: String) throws {
guard !user.isEmpty else {
throw LoginError.emptyUsername
}
guard pass == "secret" else {
throw LoginError.wrongPassword
}
print("Logged in as \(user)")
}
// call with do-catch
do {
try login(user: "Alice", pass: "secret")
} catch LoginError.emptyUsername {
print("Username is empty")
} catch LoginError.wrongPassword {
print("Wrong password")
} catch LoginError.accountLocked(let reason) {
print("Locked: \(reason)")
} catch {
// catch-all — 'error' is the thrown value
print("Unknown error: \(error)")
}try?, try!, and Result type
Swift
// try? — returns nil on failure
let result = try? login(user: "Alice", pass: "wrong")
// result is nil — no crash, error swallowed
// combine with if let
if let _ = try? login(user: "Alice", pass: "secret") {
print("Login worked")
}
// try! — crashes on failure (use rarely)
try! login(user: "Alice", pass: "secret")
// Result type — explicit success or failure
func fetchUser(id: Int) -> Result<String, Error> {
if id > 0 {
return .success("User \(id)")
} else {
return .failure(LoginError.emptyUsername)
}
}
// handle Result with switch
switch fetchUser(id: 1) {
case .success(let user):
print("Found: \(user)")
case .failure(let error):
print("Error: \(error)")
}
// or with get()
let user = try? fetchUser(id: 1).get()try! crashes your app if the function throws. Only use it when you are 100% certain failure cannot happen.
Tips & Good Habits
These habits make Swift code safer, cleaner, and easier to read. Most of them are patterns the Swift community has settled on — following them means other Swift developers will immediately feel at home in your code.
prefer let over var
Swift
// ❌ var everywhere — harder to track
var userId = 1
var userName = "Alice"
var apiURL = "https://api.example.com"
// ✅ let where the value won't change
let userId = 1
let userName = "Alice"
let apiURL = "https://api.example.com"
// var only when you actually need to change it
var retryCount = 0
retryCount += 1prefer guard over nested if let
Swift
// ❌ nested if let — hard to follow
func processOrder(
user: User?,
item: Item?,
address: Address?
) {
if let user = user {
if let item = item {
if let address = address {
// real logic buried 3 levels deep
print("Order placed")
}
}
}
}
// ✅ guard — flat and readable
func processOrder(
user: User?,
item: Item?,
address: Address?
) {
guard let user = user else { return }
guard let item = item else { return }
guard let address = address else { return }
// all values available here, no nesting
print("Order for \(user.name)")
}Deep nesting is called the 'pyramid of doom' in Swift. guard flattens it by exiting early on invalid states.
prefer struct over class
Swift
// ✅ struct for data models
// — copied safely
// — no memory management needed
// — compiler can optimise better
struct Product {
let id: Int
var name: String
var price: Double
}
// ✅ class when you need
// — inheritance
// — shared mutable state
// — interop with Objective-C
class CartManager {
static let shared = CartManager()
var items: [Product] = []
func add(_ product: Product) {
items.append(product)
}
}
// rule of thumb:
// start with struct
// switch to class when you have a specific reasonhandy one-liners worth bookmarking
Swift
// zip: combine two arrays into pairs
let names = ["Alice", "Bob", "Carol"]
let scores = [90, 85, 92]
for (name, score) in zip(names, scores) {
print("\(name): \(score)")
}
// defer: run code when scope exits (like finally)
func readFile() {
let file = openFile()
defer { file.close() } // always closes
// read file here...
}
// lazy: skip computation until it's needed
let bigList = (1...1_000_000)
.lazy
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
.first // computes only what's needed
// flatMap: flatten nested arrays
let nested = [[1, 2], [3, 4], [5, 6]]
nested.flatMap { $0 } // [1, 2, 3, 4, 5, 6]
// check type with is
let value: Any = "hello"
if value is String {
print("it's a String")
}
// cast with as?
let asString = value as? String // Optional("hello")
let asInt = value as? Int // nil — safe, no crashNo login required to share feedback
More Cheatsheets
Keep your reference handy
Explore more zero-to-hero cheatsheets for the tools you use daily.