Swift reference
Toolchain invocation, package manifests, attribute and modifier tables, the operator precedence hierarchy, the standard library's protocol structure, and the official naming conventions. The language itself is described in the Swift article; this page is the lookup companion to it.
Toolchain and command line¶
A Swift toolchain is a single download containing the compiler, standard library, package manager,
debugger, formatter, language server, and documentation compiler. On macOS it is embedded in Xcode and also
available standalone; on Linux and Windows it is installed from swift.org or through
swiftly, the official toolchain manager, which installs several toolchains side by side and
selects between them per project.
The commands that make up a Swift installation.
| Command | Purpose | Typical invocation | Notes |
|---|---|---|---|
swiftc | The compiler driver | swiftc main.swift -O -o app | Direct invocation; used for single files and by other build systems |
swift | REPL when given no arguments | swift | Interactive evaluation |
swift build | Builds the package in the current directory | swift build -c release | The normal entry point |
swift run | Builds and runs an executable product | swift run MyTool --verbose | Arguments after the target name go to the program |
swift test | Builds and runs the test targets | swift test --filter ParserTests | Runs both Swift Testing and XCTest suites |
swift package | Manifest and dependency operations | swift package resolve, update, clean | Also hosts package plugins |
swift-format | Formatter and linter | swift-format --in-place Sources/ | Ships with the toolchain since 6.0 |
sourcekit-lsp | Language server | Started by the editor | Powers VS Code, Neovim, and others |
lldb | Debugger with the Swift type checker embedded | lldb .build/debug/MyTool | Expression evaluation uses the real compiler |
docc | Documentation compiler | swift package generate-documentation | Builds the DocC archive from doc comments and articles |
Source: Swift.org toolchain documentation and swift --help for the current release.
The compiler flags that appear most often in real build configurations.
| Flag | Effect | Scope |
|---|---|---|
-swift-version 6 | Selects the language mode | Per module |
-enable-upcoming-feature X | Opts into one future behaviour early | Per module |
-strict-concurrency=complete | Full data-isolation checking in the Swift 5 mode | Per module |
-O / -Onone | Optimised / unoptimised build | Per module |
-Osize | Optimise for code size rather than speed | Per module |
-wmo | Whole-module optimisation: compile the module as one unit | Per module |
-enable-library-evolution | Emit a stable module interface for binary distribution | Per module |
-cxx-interoperability-mode=default | Enable C++ interoperability | Per module |
-sanitize=address|thread|undefined | Link a runtime sanitizer | Per build |
-warnings-as-errors | Fail the build on any warning | Per build |
-emit-sil / -emit-ir | Dump the intermediate representation | Diagnostic use |
Source: swiftc -help and the Swift compiler documentation. Package manifests set most of these through swiftSettings rather than by passing flags directly.
Swift Package Manager¶
SwiftPM is part of the toolchain, not a separate project. A package is a directory with a
Package.swift manifest, which is itself a Swift program executed by the package manager: the
first line is a swift-tools-version comment that tells SwiftPM which manifest API to compile it
against, and therefore also sets the default language mode.
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "Atlas",
platforms: [.macOS(.v14), .iOS(.v17)],
products: [
.library(name: "AtlasCore", targets: ["AtlasCore"]),
.executable(name: "atlas", targets: ["AtlasCLI"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
.package(url: "https://github.com/apple/swift-log", .upToNextMinor(from: "1.6.0")),
],
targets: [
.target(
name: "AtlasCore",
dependencies: [.product(name: "Logging", package: "swift-log")],
swiftSettings: [
.swiftLanguageMode(.v6),
.enableUpcomingFeature("ExistentialAny"),
.define("ATLAS_INTERNAL_CHECKS", .when(configuration: .debug)),
]
),
.executableTarget(
name: "AtlasCLI",
dependencies: [
"AtlasCore",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.testTarget(name: "AtlasCoreTests", dependencies: ["AtlasCore"]),
],
swiftLanguageModes: [.v6]
)
The seven target types.
| Target type | What it builds | Default source location |
|---|---|---|
.target | A library module compiled from Swift sources | Sources/<name>/ |
.executableTarget | A module with an entry point | Sources/<name>/ |
.testTarget | Test module; not built for release | Tests/<name>/ |
.macro | Compiler plugin implementing a macro | Sources/<name>/ |
.systemLibrary | Module map wrapping an installed C library | Sources/<name>/module.modulemap |
.binaryTarget | Prebuilt XCFramework or artifact bundle | Local path or remote URL with checksum |
.plugin | Build-tool or command plugin | Plugins/<name>/ |
Source: the PackageDescription API reference for tools version 6. Conventional layout means most packages need no explicit path: arguments.
Dependency resolution follows semantic versioning and records exact resolved versions in
Package.resolved, which is committed. Version requirements are expressed as
from: (up to the next major), .upToNextMinor(from:), an exact version, a branch, or
a revision; the last two are accepted for a root package but rejected in a package that is itself a
dependency, which prevents unpinned transitive requirements.
--disable-sandbox to make an error go away.
Testing¶
Two frameworks coexist. XCTest is the older, Objective-C-derived framework; Swift Testing, introduced with
Swift 6, is written for the modern language and uses macros so that a single #expect reports the
values of every sub-expression in a failed assertion. Both run under swift test and can live in
the same target, which is what makes incremental adoption practical.
The two frameworks compared on the points that affect how tests are written.
| Aspect | Swift Testing | XCTest |
|---|---|---|
| Declaration | @Test func example() | func testExample() in an XCTestCase |
| Assertions | #expect(x == y), #require | XCTAssertEqual and roughly forty siblings |
| Failure detail | Macro captures the sub-expression values | Message string supplied by the caller |
| Grouping | @Suite struct, nesting by type | Subclassing XCTestCase |
| Parameterisation | @Test(arguments:) over any collection | Manual loops or generated methods |
| Concurrency | Tests run in parallel by default; async native | Serial by default |
| Setup and teardown | init and deinit of the suite type | setUp/tearDown |
| Traits | .tags, .enabled(if:), .timeLimit | Scheme configuration |
| Platform support | All Swift platforms | All Swift platforms |
Source: the Swift Testing documentation and the XCTest reference. Swift Testing does not replace XCTest for UI and performance testing on Apple platforms, which remain XCTest-only.
import Testing
@testable import AtlasCore
@Suite("Version parsing")
struct VersionParsingTests {
@Test("Accepts well-formed semantic versions",
arguments: ["6.3.3", "1.0.0", "10.20.30"])
func parsesValid(_ input: String) throws {
let version = try #require(Version(input))
#expect(version.description == input)
}
@Test(.tags(.regression))
func rejectsTrailingText() {
#expect(Version("6.3.3-beta") == nil)
}
}
Attribute reference¶
Attributes are written with a leading @ before the declaration or type they modify. They fall
into three positions: declaration attributes, type attributes, and one switch-case attribute
(@unknown, which future-proofs a switch over a non-frozen enumeration).
Declaration attributes, grouped by what they are for rather than alphabetically.
| Attribute | Category | Effect |
|---|---|---|
@attached(...) | Macro | Declares an attached macro role |
@freestanding(...) | Macro | Declares a freestanding macro role |
@available(...) | Availability | Platform, version, deprecation, obsoletion, and noasync |
@backDeployed(before:) | Availability | Ship a function's body to older OS versions in the client |
@discardableResult | Diagnostics | Suppresses the unused-result warning |
@warn_unqualified_access | Diagnostics | Warns when a member is called without qualification |
@dynamicCallable | Dynamic | Type may be called with a keyword or positional argument list |
@dynamicMemberLookup | Dynamic | Member access is resolved at runtime by subscript |
@frozen | Evolution | Fixes stored layout or enum cases across library versions |
@inlinable | Evolution | Exposes the body to clients for cross-module inlining |
@usableFromInline | Evolution | Makes an internal symbol usable from an inlinable body |
@globalActor | Concurrency | Declares a type as a global actor |
@preconcurrency | Concurrency | Relaxes checking against pre-concurrency code |
@unchecked | Concurrency | Asserts Sendable without compiler proof |
@propertyWrapper | Metaprogramming | Declares a property wrapper type |
@resultBuilder | Metaprogramming | Declares a result-builder type |
@main | Entry point | Marks the type providing static func main() |
@objc / @nonobjc | Interop | Expose to, or hide from, the Objective-C runtime |
@objcMembers | Interop | Applies @objc to a class and its members |
@NSCopying / @NSManaged | Interop | Foundation and Core Data storage behaviour |
@testable | Testing | Import a module with internal symbols visible |
@export | Modules | Re-export definitions to client modules (documented from 6.2.3) |
Source: The Swift Programming Language, Attributes chapter. Interface Builder attributes (@IBAction, @IBOutlet, @IBDesignable, @IBInspectable) and the deprecated @UIApplicationMain/@NSApplicationMain are omitted.
The four type attributes.
| Attribute | Effect |
|---|---|
@autoclosure | Wraps the argument expression in a closure, deferring evaluation |
@escaping | The closure may outlive the call; required for stored closures |
@Sendable | The function may cross isolation boundaries |
@convention(c|block|swift) | Selects the calling convention for a function type |
Type attributes appear on a type, most often a function type in a parameter position.
@frozen and @inlinable
move implementation details into your clients' compiled binaries. Removing either later is a binary-breaking
change, so apply them only to declarations whose representation you are willing to freeze permanently, and
only in libraries built with -enable-library-evolution.
Declaration modifiers¶
Modifiers are keywords or context-sensitive keywords written between a declaration's attributes and the
keyword that introduces it. Access-level modifiers are covered in the
Access control section of the language article; each also accepts a
(set) argument to give a setter narrower access than its getter.
Non-access modifiers.
| Modifier | Effect |
|---|---|
class | Member belongs to the class itself; overridable unless final |
static | Member belongs to the type; equivalent to class final on a class |
final | Class cannot be subclassed, or member cannot be overridden |
override | Replaces a superclass member; required, so accidental shadowing is an error |
required | Every subclass must implement this initializer |
convenience | Initializer that delegates to a designated initializer |
lazy | Stored property initialised at most once, on first access |
dynamic | Dispatched through the Objective-C runtime; requires @objc |
optional | Protocol member a conforming type need not implement; @objc protocols only |
weak | Non-owning reference; must be an optional var of class type |
unowned | Non-owning, non-optional reference; traps if used after deallocation |
unowned(unsafe) | As above with no check; undefined behaviour after deallocation |
mutating / nonmutating | Whether a value-type method may modify self |
nonisolated | Actor member that is not isolated to the actor |
indirect | Enumeration case stored behind a reference, permitting recursion |
infix / prefix / postfix | Fixity of an operator declaration |
Source: The Swift Programming Language, Declarations → Declaration Modifiers.
Operators and precedence¶
Swift has no fixed operator table in the grammar. Operators are library declarations that name a precedence
group, and precedence groups declare their relations to one another with higherThan and
lowerThan. The hierarchy need only be partially ordered, so two groups may have no defined
relation, in which case their operators cannot appear adjacent without parentheses.
The eleven precedence groups used by the standard library.
| Precedence group | Associativity | Standard library operators |
|---|---|---|
BitwiseShiftPrecedence | none | << >> &<< &>> |
MultiplicationPrecedence | left | * / % & &* |
AdditionPrecedence | left | + - | ^ &+ &- |
RangeFormationPrecedence | none | ..< ... |
CastingPrecedence | left | is as as? as! |
NilCoalescingPrecedence | right | ?? |
ComparisonPrecedence | none | < <= > >= == != === !== ~= and the pointwise . forms |
LogicalConjunctionPrecedence | left | && .& |
LogicalDisjunctionPrecedence | left | || .| .^ |
TernaryPrecedence | right | ? : |
AssignmentPrecedence | right | = and the compound forms += -= *= /= %= <<= >>= &= |= ^= and the &-prefixed wrapping forms |
Source: Apple Developer, Operator Declarations. Listed in decreasing order of precedence. Prefix operators (! ~ + - ..< ...) and postfix ... bind more tightly than any infix operator.
// Declaring a new operator: fixity declaration, precedence group, implementation.
infix operator |>: ForwardPipePrecedence
precedencegroup ForwardPipePrecedence {
associativity: left
higherThan: AssignmentPrecedence
lowerThan: TernaryPrecedence
}
func |> <A, B>(value: A, transform: (A) -> B) -> B { transform(value) }
let shortNames = names |> { $0.filter { $0.count < 6 } }
// Overloading an existing operator for your own type.
extension Rectangle {
static func * (lhs: Rectangle, rhs: Double) -> Rectangle {
Rectangle(width: lhs.width * rhs, height: lhs.height * rhs)
}
}
Standard library map¶
The standard library is written in Swift and is available to every program without an import. It sits on a C++ runtime that implements the dynamic parts of the language — type metadata, generic instantiation, dynamic casting, reflection, and reference counting — and, on Apple platforms, on SDK overlays that adapt Objective-C frameworks to Swift conventions.
Fundamental types
Int, UInt, Double,
Float, Bool, String, Character,
Optional, Result.
Collections
Array, Dictionary, Set,
Range, Slice, and the lazy and reversed wrappers — all value types with
copy-on-write.
Concurrency
Task, TaskGroup,
AsyncSequence, AsyncStream, Sendable, Clock,
Duration.
Low level
UnsafePointer family, Span,
RawSpan, MemoryLayout, ManagedBuffer,
isKnownUniquelyReferenced.
The protocols a type most often adopts, and what each buys.
| Protocol | Requirement | Automatic conformance | What it unlocks |
|---|---|---|---|
Equatable | == | Synthesised when all members conform | Prerequisite for Hashable and most algorithms |
Hashable | hash(into:) | Synthesised when all members conform | Keys of Dictionary, elements of Set |
Comparable | < | Synthesised for enums without associated values | sorted(), min(), ranges |
Sequence | makeIterator() | — | for-in, map, filter |
Collection | startIndex, endIndex, subscript | — | Multi-pass traversal and indices |
Codable | init(from:), encode(to:) | Synthesised for most types | JSON and property-list serialisation |
Sendable | None — a marker protocol | Inferred for value types of Sendable members | Crossing isolation boundaries |
Identifiable | id | — | Diffable collections, SwiftUI lists |
CaseIterable | allCases | Synthesised for enums without associated values | Enumerating a closed set |
CustomStringConvertible | description | — | String(describing:) and interpolation |
Error | None — a marker protocol | — | Anything thrown |
Copyable | None — implicit | Implicit on every type | Suppress with ~Copyable |
Sources: Apple Developer standard library reference and the Protocols chapter. “Synthesised” means the compiler writes the implementation when the declaration lists the conformance.
Beyond the standard library, a set of packages maintained by the Swift project is treated as
quasi-standard: swift-collections (deque, ordered set and dictionary, heap),
swift-algorithms, swift-numerics, swift-argument-parser,
swift-log, swift-nio, and swift-syntax. The Standard Library Preview
package additionally vends accepted evolution proposals as standalone modules before they ship in the
library itself.
API design guidelines¶
Swift's naming conventions are published as normative guidelines by the Swift project, and the standard library follows them exactly. They are grammatical rather than typographical: the aim is that a call site reads as an English phrase, which is why argument labels exist as a separate concept from parameter names.
The rules that decide most naming arguments.
| Guideline | What it means |
|---|---|
| Clarity over brevity | Clarity at the point of use is the goal; brevity is a side effect of the type system, never an aim |
| Document every declaration | Write a doc comment for every declaration; difficulty describing an API is evidence of a design problem |
| Omit needless words | Every word should convey salient information at the use site |
| Name by role, not by type | Name variables and parameters for what they are used for, not their type |
| Compensate for weak type information | Add a noun describing the role when the parameter type is Any-like |
| Side effects decide the part of speech | No side effects reads as a noun phrase (x.distance(to: y)); side effects read as an imperative verb (x.sort()) |
| Boolean members read as assertions | x.isEmpty, line1.intersects(line2) |
| Protocol names | What something is reads as a noun (Collection); a capability takes “able”, “ible”, or “ing” (Equatable, ProgressReporting) |
| Label prepositional phrases | When an argument is part of a prepositional phrase, the label starts at the preposition: x.removeBoxes(havingLength: 12) |
| Omit the label on value-preserving conversions | Int64(someUInt32), not Int64(value: ...) |
| Use terms of art correctly | Prefer the common word unless a technical term is genuinely more precise; then use it strictly |
Source: Swift.org, API Design Guidelines. Reproduced in condensed form; the full document includes worked counter-examples for each rule.
Naming mutating and nonmutating method pairs.
| Case | Mutating | Nonmutating | Rule |
|---|---|---|---|
| Mutating verb | x.sort() | z = x.sorted() | Append “ed” for the nonmutating form |
| Verb with a direct object | s.stripNewlines() | t.strippingNewlines() | Append “ing” when “ed” is ungrammatical |
| Noun operation | y.formUnion(z) | x = y.union(z) | Noun names the nonmutating form; prefix “form” for the mutating one |
Mutating and nonmutating pairs must be named consistently, so that a reader can predict one from the other.
// Reads as a phrase at the point of use.
let foreground = Color(red: 32, green: 64, blue: 128)
let newPart = factory.makeWidget(gears: 42, spindles: 14)
employees.remove(at: x) // Not remove(x) - ambiguous with remove(element)
allViews.remove(cancelButton) // No label: the argument is the thing being removed
// Grammatical continuity forced into the first argument reads worse, not better.
// let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128)
// Documentation comment: a summary fragment first, then parameters and returns.
/// Returns a view of `self` containing the same elements in reverse order.
///
/// - Parameter preservingIndices: Whether index positions are retained.
/// - Returns: A lazily evaluated reversed collection.
/// - Complexity: O(1).
func reversed(preservingIndices: Bool = false) -> ReverseCollection<Self>
Documentation comments and DocC¶
Documentation comments use /// or /** */ and are written in Swift's dialect of
Markdown. DocC, the documentation compiler in the toolchain, reads them together with standalone article
files and tutorial files to produce a documentation archive that can be hosted statically or read inside
Xcode. Because the doc comments are compiled rather than scraped, a reference to a symbol that no longer
exists is a build warning.
/// A logger that records temperature measurements for one location.
///
/// Create a logger with an initial measurement, then record further readings
/// with ``update(with:)``. The maximum is maintained incrementally:
///
/// ```swift
/// let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
/// await logger.update(with: 31)
/// ```
///
/// - Note: Access from outside the actor is asynchronous.
/// - SeeAlso: ``Measurement``
public actor TemperatureLogger { }
The callouts DocC recognises include - Parameter, - Parameters,
- Returns, - Throws, - Complexity, - Precondition,
- Note, - Warning, and - SeeAlso. Double-backtick syntax
(``symbol``) creates a checked link to another symbol. Documentation is built with
swift package generate-documentation and previewed with
swift package --disable-sandbox preview-documentation.
Compilation and code generation¶
Swift does not go straight from source to LLVM IR. It introduces its own intermediate representation, SIL (Swift Intermediate Language), which is high-level enough to still know about generics, protocol conformances, ownership, and reference counting. Most of what distinguishes Swift's optimiser from a generic LLVM front end happens at that level: generic specialisation, devirtualisation of protocol witnesses, ARC traffic elimination, copy-on-write and exclusivity checking, and closure specialisation.
Why the optimisation level matters more than in C
An unoptimised Swift build leaves generic functions unspecialised, protocol calls
indirect through witness tables, and every retain and release in place. Specialisation and ARC
elimination recover most of that, so the gap between -Onone and -O is
substantially wider than the equivalent gap in C. Benchmarking a debug build tells you very little.
Module granularity
By default each file is compiled separately, so cross-file inlining and specialisation cannot happen.
Whole-module optimisation (-wmo, the default for release builds in SwiftPM and Xcode)
compiles the module as one unit. Across module boundaries, specialisation requires the body to be visible,
which is what @inlinable provides — at the cost of freezing that body into every
client.
Resilience
A library built with -enable-library-evolution accesses stored properties indirectly and
calls through a dispatch thunk, so it can add members without breaking compiled clients. That indirection
is the price of binary stability, and @frozen is how a library opts a specific type out of
it.
The seven costs that show up most often in Swift profiling.
| Cost | What it is | Usual remedy |
|---|---|---|
Existential (any P) | Boxed if larger than three words; dynamic dispatch | Use some P or a generic parameter where the type is uniform |
| Unspecialised generics | Indirect calls and opaque layout | Whole-module optimisation, or @inlinable across modules |
| Retain/release traffic | Atomic count updates on every reference copy | Value types, borrowing parameters, unowned where lifetimes allow |
| Copy-on-write copies | A full buffer copy on mutation of a shared value | reserveCapacity, in-place mutation through subscript rather than get-modify-set |
| String indexing | O(n) index arithmetic over grapheme clusters | Iterate rather than index; use utf8 when byte offsets are what you actually need |
| Dynamic casts | Runtime metadata lookup | Design out as? on hot paths |
| Objective-C bridging | Boxing and unboxing at every crossing | Keep hot loops on the Swift side of the boundary |
Sources: Swift compiler documentation and the performance discussions in the Swift forums. Every row is a trade-off the language makes deliberately, not a defect.
Swift Evolution¶
Every change to the language goes through a public process. A pitch is posted to the Swift forums for
informal discussion; if it gains traction, it is written up as a proposal in the
swiftlang/swift-evolution repository with an SE-NNNN number and a reference
implementation. A language steering group schedules a review period, typically one to two weeks, and then
publishes an acceptance, rejection, or return-for-revision with written rationale.
Pitch
Forum thread. Motivation and rough design; most proposals change substantially at this stage or stop here.
Proposal
SE-NNNN document: motivation, proposed solution, detailed
design, source-compatibility impact, alternatives considered.
Review
Scheduled and announced. Anyone may respond; the review manager summarises.
Decision
Steering group accepts, rejects, or returns for revision, with published rationale. Accepted work then ships behind a flag or in a language mode.
The process has a specific consequence for developers: a language change almost never arrives unannounced. A behaviour that will be the default in a future language mode is available first as an upcoming feature flag, so a codebase can adopt it, and be diagnosed against it, one release before it becomes mandatory. The Release model section of the language article describes how those flags combine with language modes.
Governance is distributed across workgroups — language steering, core team, and topic-specific groups for the platform ports (Android, Windows), the server ecosystem, C++ interoperability, documentation, and website. Each publishes its charter and meeting notes on swift.org.
Sources¶
- Apple Inc. and the Swift project — The Swift Programming Language (6.4 beta edition), docs.swift.org/swift-book: Attributes, Declarations, Expressions, Statements, and Summary of the Grammar.
- Swift.org — API Design Guidelines, reproduced here in condensed form.
- Swift.org — Using C++ from Swift, Standard Library, Server, and Getting Started pages.
- Swift.org — Migrating to Swift 6, the concurrency migration guide.
- Apple Developer — developer.apple.com/documentation/swift, including Operator Declarations, the source for the precedence-group table.
swiftlang/swift-package-manager—PackageDescriptionAPI reference for tools version 6.swiftlang/swift-evolution— proposal index and process documentation.
Code examples are original or adapted from the cited official documentation. Where a table condenses a longer source document, the caption names it so the full text can be consulted.