Swift cheat sheet
A scannable Swift reference: 28 short snippets across 13 topics, each linking back to the lesson it came from.
At a glance
| Topic | What it covers | |
|---|---|---|
| Syntax and optionals | An optional is a value that may be absent, written with a trailing ?. Swift will not let you use it until you have | lesson |
| Structs, classes and protocols | The compiler inserts strong references by default. A closure stored on an object that captures that object creates a | lesson |
| Closures and error handling | A closure is a function you can pass around. Swift gives it compact syntax — trailing closures, shorthand argument | lesson |
| Setting up Swift: Xcode, Swift Package Manager and Swift 6 | A common and healthy layout is a thin app target that imports one or more local packages. The logic becomes testable | lesson |
| Generics, opaque types and protocol design | Favour protocol composition (Codable & Sendable) over deep inheritance, and inject dependencies as protocol | lesson |
| Collections, strings and the standard library | Arrays, dictionaries and sets, map and filter and reduce, String versus Substring, Unicode and grapheme clusters, Date | lesson |
| Swift 6 concurrency: tasks, actors and Sendable | Task and TaskGroup, async let, actor isolation, MainActor, Sendable checking, structured cancellation and the data-race | lesson |
| SwiftUI: views, state and navigation | A typed path array is the whole navigation state. Because it is a value, you can save it, restore it, or test a deep | lesson |
| Networking, persistence and Codable | URLSession with async and await, JSONDecoder and CodingKeys, mapping errors, caching, UserDefaults, file storage and | lesson |
| Testing with XCTest and Swift Testing | A protocol and a stub is usually enough. Reach for a generated mock only when you need to verify call order or argument | lesson |
| Memory management, ARC and performance | Strong, weak and unowned references, capture semantics, value-type copying, autorelease, and using Instruments to find | lesson |
| Macros, property wrappers and result builders | Write a property wrapper, build a result builder, understand the macro system and its limits, and know how to read | lesson |
| Packaging, build configuration and distribution | An unshared scheme lives only on the machine that created it. Commit the scheme, or CI will fail with a message about a | lesson |
Quick snippets
Syntax and optionals
Values, functions, control flow
let name = "Ada" // constant, type inferred as String
var score = 0 // variable
let ratio: Double = 0.75 // explicit type when it is not obvious
func greet(_ who: String, greeting: String = "Hello") -> String {
return greeting + ", " + who
}
greet("Ada") // "Hello, Ada"
greet("Ada", greeting: "Welcome") // argument labels are part of the API
let label = score == 0 ? "empty" : "scored"… 11 more lines in the full lesson.
Optionals
struct User {
let email: String
let phone: String?
}
func contact(_ user: User?) -> String {
guard let email = user?.email, !email.isEmpty else { return "unknown" }
let phone = user?.phone ?? "no phone"
return email + " / " + phone
}
let maybe: Int? = Int("42") // Int("abc") would be nil, not a crash… 6 more lines in the full lesson.
Full lesson: Syntax and optionals →
Structs, classes and protocols
Structs: value semantics
struct Point: Equatable {
var x: Double
var y: Double
// memberwise init is generated, so Point(x: 1, y: 2) already works
}
struct Counter {
private(set) var value = 0
mutating func increment() { value += 1 } // mutating: changes a value type
}… 8 more lines in the full lesson.
Classes and inheritance
class Account {
let owner: String
private(set) var balance: Int
init(owner: String, opening: Int = 0) {
self.owner = owner
self.balance = opening
}
func deposit(_ amount: Int) {
precondition(amount > 0, "amount must be positive")
balance += amount… 13 more lines in the full lesson.
Protocols and default implementations
protocol Identifiable {
var id: String { get }
}
protocol Persistable {
func save() throws
func describe() -> String
}
extension Persistable {
func describe() -> String { return "record " + id } // reusable default
}… 16 more lines in the full lesson.
Full lesson: Structs, classes and protocols →
Closures and error handling
Closures
let numbers = [3, 1, 2]
// full form
let sorted1 = numbers.sorted(by: { (a: Int, b: Int) -> Bool in a < b })
// shorthand argument names, implicit return
let sorted2 = numbers.sorted { $0 < $1 }
var completions: [() -> Void] = []
func loadRemote(with completion: @escaping (Result<String, Error>) -> Void) {
completions.append(completion) // escaping: outlives the call
}… 11 more lines in the full lesson.
Throwing and catching
enum ParseError: Error, Equatable {
case empty
case notANumber(String)
}
func parse(_ text: String) throws -> Int {
let trimmed = text.trimmingCharacters(in: .whitespaces)
guard !trimmed.isEmpty else { throw ParseError.empty }
guard let value = Int(trimmed) else { throw ParseError.notANumber(trimmed) }
return value
}
… 13 more lines in the full lesson.
Errors with async and await
func fetchUser(id: String) async throws -> User {
let (data, response) = try await URLSession.shared.data(from: url)
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
throw ParseError.empty
}
return try JSONDecoder().decode(User.self, from: data)
}
func load() async {
do {
let user = try await fetchUser(id: "42")
print(user.email)… 6 more lines in the full lesson.
Full lesson: Closures and error handling →
Setting up Swift: Xcode, Swift Package Manager and Swift 6
Toolchain and project choices
# install a toolchain from swift.org, or use the one inside Xcode
swift --version
swiftly install latest # a version manager, keeps several toolchains side by side
swiftly use 6.0.3
xcrun --sdk macosx --show-sdk-version
Building without Xcode
swift package init --type library
swift build # debug
swift build -c release
swift test --parallel
swift run reports-cli --help
swift package show-dependencies --format json
swift package resolve # after editing Package.swift
swift package diagnose-api-breaking-changes 1.2.0
Reading a Package.swift
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "Reports",
platforms: [.macOS(.v14), .iOS(.v17)],
products: [
.library(name: "ReportsCore", targets: ["ReportsCore"]),
.executable(name: "reports-cli", targets: ["ReportsCLI"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"),… 16 more lines in the full lesson.
Full lesson: Setting up Swift: Xcode, Swift Package Manager and Swift 6 →
Generics, opaque types and protocol design
Generic functions and constraints
func firstIndex<T: Collection>(of value: T.Element, in collection: T) -> T.Index?
where T.Element: Equatable {
collection.firstIndex(of: value)
}
// a where clause on the extension, not on every method
extension Sequence where Element: Numeric {
func total() -> Element { reduce(.zero, +) }
}
[1, 2, 3].total() // 6
[1.5, 2.5].total() // 4.0… 12 more lines in the full lesson.
some versus any
protocol Shape {
func area() -> Double
}
struct Circle: Shape {
let radius: Double
func area() -> Double { .pi * radius * radius }
}
// opaque: the caller knows it is a Shape, the concrete type stays private
func makeDefaultShape() -> some Shape { Circle(radius: 1) }
… 10 more lines in the full lesson.
Full lesson: Generics, opaque types and protocol design →
Collections, strings and the standard library
Choosing the right container
var scores: [String: Int] = ["ada": 91, "grace": 87]
let visited: Set<String> = ["home", "search", "home"] // two elements
scores["linus"] = 78
scores["ada", default: 0] += 5 // avoids a force unwrap
let grouped = Dictionary(grouping: scores.keys, by: { $0.first! })
let sorted = scores.sorted { $0.value > $1.value }
let top = scores.max { $0.value < $1.value } // ("ada", 96)
// transform in one pass instead of building intermediate arrays
let summary = scores… 7 more lines in the full lesson.
Strings, Substring and Unicode
let text = "Café naïve" // combining marks
text.count // 11 grapheme clusters, not 13 scalars
text.utf8.count // bytes on the wire
text.unicodeScalars.count // scalars
let index = text.index(text.startIndex, offsetBy: 4)
let prefix = text[..<index] // Substring, shares storage with text
// a Substring keeps the whole original string alive; convert when it escapes
let piece: String = String(prefix)
… 7 more lines in the full lesson.
Dates, calendars and Codable
let now = Date.now
let calendar = Calendar(identifier: .gregorian)
let startOfDay = calendar.startOfDay(for: now)
let days = calendar.dateComponents([.day, .month, .year], from: now)
let formatter = Date.FormatStyle(date: .abbreviated, time: .shortened)
.locale(Locale(identifier: "en_GB"))
let label = now.formatted(formatter)
// time zones change; a Date is an instant, not a wall-clock time
let deadline = calendar.date(byAdding: .day, value: 30, to: now)!
let daysLeft = calendar.dateComponents([.day], from: now, to: deadline).day ?? 0… 15 more lines in the full lesson.
Full lesson: Collections, strings and the standard library →
Swift 6 concurrency: tasks, actors and Sendable
Data-race safety in practice
// WRONG in Swift 6: the closure runs off the main actor
// and touches main-actor state without isolation
@MainActor
final class Feed {
var items: [String] = []
func load() async {
let fetched = await fetchItems()
items = fetched // ok: still on the main actor
}
}
… 12 more lines in the full lesson.
Full lesson: Swift 6 concurrency: tasks, actors and Sendable →
SwiftUI: views, state and navigation
Connecting a view to async data
struct ArticleDetail: View {
let id: Int
@State private var article: Article?
@State private var error: String?
var body: some View {
Group {
if let article {
ScrollView {
Text(article.title).font(.title)
Text(article.body)
}… 16 more lines in the full lesson.
Full lesson: SwiftUI: views, state and navigation →
Networking, persistence and Codable
Caching and background refresh
actor ArticleCache {
private var entries: [Int: (article: Article, savedAt: Date)] = [:]
func article(_ id: Int, maxAge: TimeInterval = 300) -> Article? {
guard let entry = entries[id],
Date.now.timeIntervalSince(entry.savedAt) < maxAge else { return nil }
return entry.article
}
func store(_ article: Article) {
entries[article.id] = (article, .now)
}… 8 more lines in the full lesson.
Full lesson: Networking, persistence and Codable →
Testing with XCTest and Swift Testing
Running tests in CI
# packages: fast, no simulator needed
swift test --parallel --enable-code-coverage
# Apple apps: a specific simulator, result bundle for the report
xcodebuild test \
-scheme App -destination 'platform=iOS Simulator,name=iPhone 16' \
-enableCodeCoverage YES -resultBundlePath build/TestResults.xcresult
xcrun xccov view --report --json build/TestResults.xcresult > coverage.jsonFull lesson: Testing with XCTest and Swift Testing →
Memory management, ARC and performance
Profiling with Instruments
# leaks and allocations while exercising the app
xcrun xctrace record --template "Leaks" \
--launch com.example.app --output leaks.trace --time-limit 90s
# what is burning CPU during a specific interaction
xcrun xctrace record --template "Time Profiler" \
--launch com.example.app --output cpu.trace --time-limit 60s
# memory graph in Xcode: Debug > Memory Graph while the suspicious screen is open
ARC and reference cycles
final class Node {
let name: String
var parent: Node? // strong by default: a cycle with children
weak var delegate: NodeDelegate?
init(name: String) { self.name = name }
}
// the classic cycle: a closure stored on the object captures self
final class Loader {
var onFinish: (() -> Void)?
… 15 more lines in the full lesson.
Value types and copying
// copy-on-write: assignment is cheap until a mutation happens
var first = Array(repeating: 0, count: 1_000_000)
var second = first // no copy yet, both share the buffer
second[0] = 1 // now the buffer is copied exactly once
print(first[0], second[0]) // 0 1
// a large struct passed around is copied unless the compiler proves otherwise,
// so build it once and return it rather than through several transformation steps
struct Report { let rows: [Row]; let totals: [String: Decimal] }
func makeReport(_ rows: [Row]) -> Report {
Report(rows: rows, totals: rows.reduce(into: [:]) { totals, row in… 3 more lines in the full lesson.
Full lesson: Memory management, ARC and performance →
Macros, property wrappers and result builders
Property wrappers
@propertyWrapper
struct Clamped<Value: Comparable> {
private var value: Value
private let range: ClosedRange<Value>
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: Value {
get { value }… 14 more lines in the full lesson.
Macros and generated code
// A freestanding macro expands at the call site
let name = #function
let file = #filePath
let warning = #warning("remove before release")
// An attached macro augments a declaration: the compiler requires
// a peer declaration generated by a compiler plugin.
@freestanding(expression)
macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacrosImpl", type: "StringifyMacro")
@attached(member, names: named(init(from:)))
public macro Codable() = #externalMacro(module: "MacrosImpl", type: "CodableMacro")… 8 more lines in the full lesson.
Full lesson: Macros, property wrappers and result builders →
Packaging, build configuration and distribution
Distribution
# archive and export for the App Store
xcodebuild archive -project App.xcodeproj -scheme App \
-destination "generic/platform=iOS" -archivePath build/App.xcarchive
xcodebuild -exportArchive -archivePath build/App.xcarchive \
-exportOptionsPlist Config/ExportOptions.plist -exportPath build/ipa
# server-side Swift on Linux
swift build -c release --static-swift-stdlib
docker build -t registry.example.com/reports:1.4.0 .
docker push registry.example.com/reports:1.4.0
Build settings and xcconfig
// Config/Shared.xcconfig
PRODUCT_BUNDLE_IDENTIFIER = com.example.app
MARKETING_VERSION = 2.4.0
CURRENT_PROJECT_VERSION = 1
SWIFT_VERSION = 6.0
SWIFT_STRICT_CONCURRENCY = complete
ENABLE_USER_SCRIPT_SANDBOXING = YES
// Config/Debug.xcconfig
#include "Shared.xcconfig"
BUNDLE_ID_SUFFIX = .debug
API_BASE_URL = https:/$()/staging.api.example.com… 6 more lines in the full lesson.
Dependencies and schemes
// a shared scheme committed to the repository is what CI runs
// App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
let scheme = """
<Scheme LastUpgradeVersion="1600" version="1.7">
<TestAction buildConfiguration="Debug">
<Testables>
<TestableReference skipped="NO">
<BuildableReference BuildableIdentifier="primary"
BlueprintName="AppTests" BuildableName="AppTests.xctest"
ReferencedContainer="container:App.xcodeproj"/>
</TestableReference>
</Testables>… 3 more lines in the full lesson.
Full lesson: Packaging, build configuration and distribution →
FAQ
Is this Swift cheat sheet free to use?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
Android iOS Flutter React Native Kotlin
Last refreshed 2026-09-27.