Swift Keywords and Syntax Quick Reference
🟪 Syntax · 🟦 Types/APIs · 🟩 Correct pattern · 🟥 Bug · 🟨 Gotcha · 🧠 Explanation
This is a grouped reference for the Swift 6.4 language. Some words are reserved everywhere; others are only special in a grammar position. A spelling being used as a keyword in one declaration does not always prevent using it as a name elsewhere. Escape a reserved spelling with backticks only when there is a good interoperability reason.
Declarations and modifiers
| Keyword | Typical role |
|---|---|
associatedtype | Declares a protocol-associated type |
borrowing | Specifies a non-consuming parameter ownership convention |
actor | Declares an actor-isolated reference type |
class | Declares a reference type; also marks overridable type members |
consuming | Specifies that a parameter consumes a value |
deinit | Defines class/actor cleanup before deallocation |
enum | Declares a type with a finite set of cases, possibly carrying values |
extension | Adds methods, computed properties, conformances, and nested types |
fileprivate | Makes a declaration accessible within its source file |
func | Declares a function or method |
import | Makes declarations from a module available |
init | Declares an initializer |
inout | Allows a function to mutate a caller's variable |
internal | Default access; visible within the current module |
let | Declares an immutable binding |
macro | Declares a Swift macro |
nonisolated | Marks a declaration as not isolated to its actor/global actor |
open | Allows access and subclassing/overriding outside the defining module |
operator | Declares a custom operator |
precedencegroup | Defines precedence and associativity for operators |
private | Restricts access to the enclosing declaration scope |
protocol | Declares a set of requirements |
public | Exposes a declaration to importing modules |
rethrows | Can throw only when a throwing function argument throws |
static | Declares a type-level member or a non-overridable class member |
struct | Declares a value type |
subscript | Defines indexed get/set syntax |
typealias | Gives an existing type another name |
var | Declares mutable storage or a computed property |
actor and macro are special in their declaration grammar. async, throws, access control, and ownership modifiers also appear in the declaration forms below.
import Foundation
protocol IdentifiableRecord {
associatedtype ID: Hashable
var id: ID { get }
}
struct Record: IdentifiableRecord {
let id: UUID
private(set) var title: String
}
actor RecordStore {
private var records: [UUID: Record] = [:]
func record(id: UUID) -> Record? { records[id] }
}Control-flow and statement keywords
break, case, catch, continue, default, defer, do, else, fallthrough, for, guard, if, in, repeat, return, switch, throw, where, while.
import Foundation
struct Record {
let title: String
}
enum LookupError: Error {
case missing
}
func title(for record: Record?) throws -> String {
guard let record else { throw LookupError.missing }
defer { print("finished lookup") }
switch record.title.count {
case 0: return "Untitled"
case 1...20 where record.title.first?.isUppercase == true:
return record.title
default:
return String(record.title.prefix(20))
}
}guardexits the current scope unless its condition succeeds.deferruns when the current scope exits. In Swift 6.4 async functions can also use asynchronous cleanup insidedefer.fallthroughexplicitly continues into the nextswitchcase. Most Swift switches should use independent cases instead.whereadds a condition to a pattern or generic constraint.repeatbegins arepeat-whileloop, which checks its condition after its body.
Expression and type keywords
Any, as, await, catch, false, is, nil, rethrows, self, Self, super, throw, throws, true, try.
import Foundation
func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
try JSONDecoder().decode(type, from: data)
}
func loadValue() async throws -> Any { "ready" }
func use(_ value: Any) async throws {
let loaded = try await loadValue()
if loaded is String { /* type test */ }
let string = value as? String // conditional cast
let required = value as! String // forced cast; use only for a proven invariant
let unknown: Any = 42 // any value, without a specific protocol contract
}trymarks a throwing call,try?converts failure to an optional, andtry!traps on failure.awaitmarks a possible suspension while calling asynchronous work.Selfis the current type;selfis the current value/instance.Anycan hold any value.any SomeProtocolis an existential with a protocol contract.as?is a conditional cast;as!traps if the cast fails. Avoid force casts in normal control flow.
Context-sensitive keywords
These spellings are special in particular grammar positions and can be ordinary identifiers in other positions:
| Group | Words |
|---|---|
| Access / dispatch | convenience, dynamic, final, override, required, package |
| Properties | didSet, get, lazy, set, willSet |
| Operators / enums | associativity, indirect, infix, left, none, postfix, precedence, prefix, right |
| Mutation / ownership | mutating, nonmutating, weak, unowned |
| Concurrency / type spelling | async, some, Protocol, Type |
| Optional Objective-C protocol members | optional |
import SwiftUI
@MainActor
final class SettingsModel {
lazy var formatter = DateFormatter()
private(set) var title = "Settings" {
didSet { print("title changed") }
}
func refresh() async throws {
title = try await fetchTitle()
}
private func fetchTitle() async throws -> String { "Settings" }
}
func makeLabel() -> some View { Text("Ready") }The compiler's current language reference is the final authority for context-sensitive spellings. distributed, sending, and isolation-related terms also appear in newer concurrency grammar.
Directives and compiler macros
The following # forms are language directives or macros, not ordinary declaration keywords:
| Form | Purpose |
|---|---|
#if, #elseif, #else, #endif | Conditional compilation |
#available, #unavailable | Runtime OS availability checks |
#keyPath, #selector | Objective-C/KVO interoperability |
#sourceLocation | Adjust source location information |
#colorLiteral, #imageLiteral, #fileLiteral | Xcode literal support |
#file, #fileID, #filePath, #function, #line, #column, #dsohandle | Source/compiler context values |
#warning(...), #error(...) | Emit build diagnostics |
#Preview | Declare a SwiftUI preview (macro) |
#expect, #require, @Test, @Suite | Swift Testing macros/attributes |
if #available(iOS 17, *) {
// Use an API introduced in iOS 17 or later.
} else {
// Keep a fallback for the deployment target.
}
#if DEBUG
print("Debug build")
#endif@Observable, @State, @MainActor, and @available use attribute syntax. The @ forms are not keywords in the same category as if or func.
Common attributes and property wrappers worth recognizing include @MainActor, @concurrent, @Sendable, @Observable, @State, @Binding, @Bindable, @available, @objc, @discardableResult, @inlinable, and Swift 6.4's @diagnose for source-level warning control. The @ syntax does not make every attribute part of the Swift language grammar; many are provided by the standard library or frameworks.
Common punctuation with meaning
| Syntax | Meaning |
|---|---|
? | Optional type (User?), optional chaining (user?.name), or ternary conditional |
! | Force unwrap (user!) or logical negation (!isReady) |
-> | Function result type |
_ | Wildcard pattern or ignored argument label |
... / ..< | Closed / half-open range |
& | Inout argument marker or protocol composition separator |
\.name | Key path |
$value | Property-wrapper projection, commonly a Binding or publisher |
\(value) | String interpolation |
... in a declaration | Variadic parameter syntax (String...) |
Swift 6.4 syntax worth recognizing
These are recent language capabilities; use them only when the project's compiler and language mode support them:
// Optional opaque/existential type spelling in Swift 6.4:
func maybeView(_ show: Bool) -> some View? {
show ? Text("Ready") : nil
}
// Explicit ownership conventions for an advanced noncopyable type:
struct Resource: ~Copyable { let handle: Int }
func inspect(_ resource: borrowing Resource) { print(resource.handle) }
func consume(_ resource: consuming Resource) { print(resource.handle) }
// Module selector when two imports export the same name:
let task = Swift::Task { /* work */ }
// Async cleanup is awaited when the scope exits (in an async function):
func useResource() async throws {
let resource = try await openResource()
defer { await resource.close() }
try await resource.process()
}Naming and safe defaults
- Prefer
let; usevaronly when reassignment or mutation is required. - Prefer
guard letfor required input validation andif letfor optional branches. - Prefer
as?andtry?only when a failed cast/operation is a normal optional outcome. - Keep access control narrow:
privateinside a type,internalinside a module,packageinside a Swift package,publicfor APIs, andopenonly when external subclassing is part of the API contract. - Avoid
!,as!,try!, andfatalErrorfor ordinary recoverable failures.
