Swift Cheat Sheet
Optionals, closures, protocols, generics, actors and SwiftUI in one Swift cheat sheet. Every snippet is copy ready, filterable and cross referenced.
Basics
Constants, variables, type inference and string interpolation. Swift is statically typed but you rarely write the type out.
Types & Operators
Swift never converts numeric types for you. That verbosity is deliberate: it removes a whole family of silent precision bugs.
| Type | Holds | Notes |
|---|---|---|
| Int | whole numbers | 64 bit on modern devices, the default |
| UInt8 ... UInt64 | unsigned | use only for bit work and byte buffers |
| Double | 64 bit float | the default for decimals |
| Float | 32 bit float | graphics and memory constrained data |
| Bool | true or false | no integer coercion at all |
| String | Unicode text | value type, grapheme cluster based |
| Character | one grapheme | can be several Unicode scalars |
| Array<T> | ordered list | written [T] |
| Dictionary<K,V> | key to value | written [K: V] |
| Set<T> | unique, unordered | T must be Hashable |
| Optional<T> | value or nil | written T? |
| Void | no value | the empty tuple () |
| Any / AnyObject | any / any class | escape hatch, avoid in new code |
| Operator | Meaning |
|---|---|
| + - * / % | arithmetic, % is remainder and works on Int only |
| == != < > <= >= | comparison, needs Equatable or Comparable |
| === !== | identity, do two references point at the same object |
| && || ! | logical, short circuits |
| ?? | nil coalescing, supply a default |
| ?. | optional chaining |
| ! | force unwrap, crashes on nil |
| ... ..< | closed range and half open range |
| &+ &- &* | wrapping arithmetic, no overflow trap |
| ~= | pattern match, what switch case uses |
| & | ^ << >> ~ | bitwise |
| is as? as! as | type check and cast |
Optionals
Swift has no implicit null. A value that may be absent has type T?, and the compiler will not let you use it until you deal with the nil case.
The unwrapping decision, in order
Strings
Swift strings are Unicode correct by design. That is why you index them with String.Index instead of Int, and why count is not a constant time lookup.
Collections
Array, Dictionary and Set are all value types with copy on write, so passing one around is cheap until somebody mutates it.
Control Flow
Switch is exhaustive and pattern matching runs deep. Most of the branching you would write with if elsewhere becomes a switch here.
Functions & Closures
Argument labels make call sites read like sentences. Closures are first class, and trailing closure syntax is why SwiftUI looks the way it does.
Structs & Classes
The choice between value and reference semantics is the most consequential design decision in a Swift codebase. Start with a struct.
| Aspect | struct | class |
|---|---|---|
| semantics | value, copied on assignment | reference, shared |
| memberwise init | generated for free | you write it |
| inheritance | no, compose with protocols | yes, single superclass |
| mutation | methods need mutating | free, even on a let |
| deinit | not available | available |
| identity | none, compare by value | === compares identity |
| thread safety | easy, copies are independent | needs care, shared state |
| storage | usually inline or in the parent | always heap, ARC counted |
| reach for it when | models, values, most types | identity, shared state, ObjC interop |
Enums
Swift enums carry data, conform to protocols and have methods. Used well they make illegal states impossible to represent.
Protocols
Protocols describe capability rather than ancestry. With protocol extensions they also carry default behaviour, which is why Swift leans on composition instead of inheritance.
| Protocol | Gives you |
|---|---|
| Equatable | == and !=, synthesised for simple types |
| Hashable | use as a Dictionary key or in a Set |
| Comparable | < > and sorted() |
| Codable | encode to and decode from JSON and more |
| Identifiable | a stable id, required by SwiftUI lists |
| CustomStringConvertible | your own description in print |
| Sequence / Collection | for in, map, filter and the rest |
| IteratorProtocol | drive a custom Sequence |
| ExpressibleByStringLiteral | init your type from a literal |
| RawRepresentable | raw value conversion, usually via enums |
| Error | throwable, usually an enum |
| Sendable | safe to cross a concurrency boundary |
| OptionSet | bit flag style sets |
| AsyncSequence | for await iteration |
Generics
Write once, work with every type that satisfies the constraint, with no boxing and no loss of type information.
Error Handling
Swift errors are values, not exceptions. A function that can fail says so in its signature, and the compiler makes callers acknowledge it.
Properties & Access Control
Computed properties, observers and wrappers cover most of what you would write boilerplate for elsewhere.
| Level | Visible to |
|---|---|
| private | the enclosing declaration and its extensions in the same file |
| fileprivate | everything in the same file |
| internal | the whole module, this is the default |
| package | every module in the same package, Swift 5.9 |
| public | other modules, but not subclassable outside |
| open | other modules, and subclassable or overridable there |
Memory & ARC
Automatic Reference Counting frees objects the moment the last strong reference disappears. The only thing it cannot solve for you is a cycle.
The three reference kinds
Concurrency
Structured concurrency replaced callback pyramids. Under Swift 6 strict checking, data races become compile errors instead of intermittent crashes.
SwiftUI
Views are values that describe the interface for the current state. You never mutate a view, you change state and let the framework rebuild.
UIKit
Most shipping iOS code is still UIKit, and mixed UIKit and SwiftUI apps are the norm. Here is the imperative half of the platform.
Persistence
SwiftData is the modern declarative store. Core Data still runs underneath it and is what most existing apps use.
Foundation & Codable
JSON, dates, files and networking. Codable in particular removes most of the parsing code you would otherwise hand write.
Testing
Swift Testing is the modern framework built around macros and plain expressions. XCTest is still everywhere, and the two run side by side.
Debugging & LLDB
The debugger console is faster than another print and rebuild cycle. These are the commands worth knowing by heart.
| Command | What it does |
|---|---|
| po value | print the object description |
| p value | print with type information |
| v value | print a variable without running code |
| e expression | evaluate, and it can mutate state |
| e -l swift -- code | force the Swift language context |
| bt | backtrace for the current thread |
| bt all | backtrace for every thread |
| frame variable | list everything in the current frame |
| frame select 2 | move up the stack |
| thread step-over (n) | step over one line |
| thread step-in (s) | step into the call |
| continue (c) | resume execution |
| b MyType.method | set a symbolic breakpoint |
| br list / br delete | list or remove breakpoints |
| watchpoint set variable x | break when x changes |
| image lookup -a address | resolve a crash address to a symbol |
| expr -O -- object | description of a complex object |
Package Manager & Tooling
Swift Package Manager ships with the toolchain and is the default way to build, test and depend on code, inside Xcode and on the command line alike.
| Command | What it does |
|---|---|
| swift package init | scaffold a new package |
| swift build | compile in debug |
| swift build -c release | compile optimised |
| swift run | build and run the executable |
| swift test | run the test targets |
| swift test --filter Parser | run a subset |
| swift package resolve | fetch and pin dependencies |
| swift package update | move within the allowed ranges |
| swift package show-dependencies | print the dependency tree |
| swift package clean | delete the build folder |
| swift-format -i -r Sources | format in place |
| xcrun swift-format lint | lint without rewriting |
| xcodebuild -scheme App test | run tests in CI |
| Keys | Action |
|---|---|
| Cmd R | run |
| Cmd U | run tests |
| Cmd B | build |
| Cmd Shift K | clean build folder |
| Cmd Shift O | open quickly, jump to any symbol |
| Ctrl Cmd J | jump to definition |
| Ctrl Cmd Left | go back |
| Cmd Shift F | find in project |
| Ctrl I | re-indent selection |
| Cmd / | toggle comment |
| Cmd Ctrl E | rename in scope |
| Cmd Shift A | quick actions menu |
| Cmd Opt P | resume the preview canvas |
| Cmd Shift Y | toggle the debug area |
Macros & Attributes
Attributes steer the compiler. Macros, added in Swift 5.9, generate real source code at build time and are fully type checked.
| Attribute | Meaning |
|---|---|
| @main | marks the program entry point |
| @escaping | the closure outlives the call |
| @autoclosure | wrap the argument in a closure automatically |
| @discardableResult | no warning if the return value is ignored |
| @available | gate on OS version or mark deprecated |
| @inlinable | expose the body for cross module inlining |
| @MainActor | isolate to the main actor |
| @Sendable | the closure is safe to send across tasks |
| @objc / @objcMembers | expose to the Objective-C runtime |
| @dynamicMemberLookup | resolve arbitrary members at compile time |
| @resultBuilder | build values from a statement list, as SwiftUI does |
| @frozen | promise the layout will not change, ABI stability |
| @testable | import a module with internal access |
Compiler Error Index
The messages that actually stop people, each with the smallest reproduction and the fix that resolves it.
Coming From Another Language
Direct translations for what you already know how to do. Find the habit on the left, learn its Swift spelling on the right.
| Objective-C | Swift |
|---|---|
| NSString * | String |
| NSArray / NSMutableArray | let [T] / var [T] |
| NSDictionary | [K: V] |
| NSNumber | Int, Double, Bool |
| nil check on every call | Optional plus if let |
| id | Any or AnyObject |
| @property (nonatomic, strong) | var |
| @property (weak) | weak var |
| @interface / @implementation | one struct or class, no header |
| @protocol | protocol |
| categories | extension |
| blocks | closures |
| NSError ** | throws |
| #import | import, no header files |
| Kotlin | Swift |
|---|---|
| val / var | let / var |
| String? | String? |
| ?: elvis | ?? nil coalescing |
| ?.let { } | if let |
| data class | struct with Equatable and Hashable |
| sealed class | enum with associated values |
| when | switch |
| interface | protocol |
| companion object | static members |
| extension functions | extension |
| suspend fun | async func |
| coroutineScope | withTaskGroup |
| Flow | AsyncSequence or AsyncStream |
| listOf / mutableListOf | let [T] / var [T] |
| TypeScript | Swift |
|---|---|
| const / let | let / var |
| string | undefined | String? |
| ?? and ?. | ?? and ?. |
| interface / type | protocol / struct |
| union type A | B | enum with associated values |
| Array<T> / T[] | [T] |
| Record<K, V> | [K: V] |
| map / filter / reduce | map / filter / reduce |
| async / await | async / await, plus try |
| Promise.all | async let, or a task group |
| try / catch | do / catch with throws |
| JSON.parse | JSONDecoder().decode |
| npm install | add to Package.swift |
| generics <T extends X> | <T: X> |
| Python | Swift |
|---|---|
| x = 5 | let x = 5 |
| list / dict / set | [T] / [K: V] / Set<T> |
| None | nil, inside an Optional |
| len(x) | x.count |
| f"{name}" | "\(name)" |
| [f(x) for x in xs] | xs.map(f) |
| [x for x in xs if p(x)] | xs.filter(p) |
| for i, v in enumerate(xs) | for (i, v) in xs.enumerated() |
| class / @dataclass | class / struct |
| try / except | do / catch |
| raise ValueError | throw MyError.invalid |
| with open(p) as f | defer for cleanup |
| json.loads | JSONDecoder().decode |
| pytest | swift test |