Chapter 1: The Basics
This chapter introduces the fundamental building blocks of the Swift language, including constants, variables, numeric types, type safety, optionals, error handling, and assertions.
Constants and Variables
Constants and variables associate a name with a value.
A constant cannot be changed after it receives a value.
A variable can be assigned a different value later.
Declaring Constants and Variables
Use let to declare a constant.
Use var to declare a variable.
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
In this example:
- maximumNumberOfLoginAttempts is a constant because its value never changes.
- currentLoginAttempt is a variable because its value changes over time.
If a value does not need to change, prefer a constant.
Constants make code safer and communicate intent more clearly.
Delayed Initialization
A constant or variable can be declared without an initial value and assigned later.
Before a value can be be read, Swift requires it to be initialized.
A constant can be assigned exactly once.
var environment = "development"
let maximumNumberOfLoginAttempts: Int
if environment == "development" {
maximumNumberOfLoginAttempts = 100
} else {
maximumNumberOfLoginAttempts = 10
}
In this example, the constant's value depends on the environment.
Swift guarantees that every execution path assigns a value before the constant can be used.
Multiple Declarations
Multiple constants or variables can be declared on a single line.
var x = 0.0, y = 0.0, z = 0.0
Type Annotations
A type annotation explicitly declares the type a constant or variable can store.
Use a colon followed by the type name.
var welcomeMessage: String
This can be read as:
Declare a variable named welcomeMessage of type String.
The declaration above creates a variable that can store String values.
The variable can be assigned a value later.
welcomeMessage = "Hello"
Multiple Variables
Multiple variables of the same type can share a single type annotation.
var red, green, blue: Double
Each variable in this declaration stores a Double value.
When To Use Type Annotations
Swift can often determine a type automatically using type inference.
Type annotations are useful when:
- The type cannot be inferred clearly.
- You want to make the intended type explicit.
- You are declaring a value before assigning its initial value.
let maximumNumberOfLoginAttempts: Int
In this example, Swift knows the constant will store an Int value even though a value has not yet been assigned.
Naming Constants and Variables
Choose names that clearly describe the value they represent.
Swift names can contain almost any Unicode character, including non-Latin characters and emoji.
let π = 3.14159
let 🐶🐮 = "dogcow"
Naming Rules
Names can contain:
- Letters
- Numbers
- Unicode characters
- Emoji
Names cannot:
- Contain whitespace characters
- Begin with a number
let 1stPlace = "Gold" // Error
let firstPlace = "Gold" // Valid
Swift is a case-sensitive language.
These names are different:
var friendlyWelcome = "Hello!"
var FriendlyWelcome = "Hello!"
Reserved Keywords
Swift reserves certain words for its own use.
Examples include:
- class
- struct
- enum
- protocol
These keywords cannot normally be used as names.
let class = "Example" // Error
Using Keywords As Names
If necessary, a reserved keyword can be used as a name by surrounding it with backticks.
let `class` = "Example"
This allows the keyword to be treated as an identifier instead of a Swift language keyword.
Naming Conventions
Use names that communicate intent clearly.
A good name should help explain the purpose of the value without requiring additional comments.
let maximumNumberOfLoginAttempts = 10
Descriptive names are generally preferred over short or ambiguous names.
Printing Constants and Variables
Use print() to display the current value of a constant or variable.
var friendlyWelcome = "Hello!"
print(friendlyWelcome)
Hello!The value stored in friendlyWelcome is written to the console.
String Interpolation
String interpolation inserts a constant, variable, expression, or function call directly into a string.
Use the following syntax:
\(value)
Example:
print("The current value of friendlyWelcome is \(friendlyWelcome)")
The current value of friendlyWelcome is Hello!Swift evaluates the expression and inserts the result into the string.
Expressions in String Interpolation
String interpolation is not limited to variables.
Expressions can also be evaluated.
print("Two times two is \(2 * 2)")
Two times two is 4The expression is evaluated before the final string is produced.
Why String Interpolation Is Preferred
String interpolation is the standard way to combine values and text in Swift.
It improves readability and avoids manually joining strings together.
let score = 100
print("Score: \(score)")
Comments
Comments describe code and are ignored by the Swift compiler.
Use comments to explain intent, assumptions, or important implementation details.
Single-Line Comments
Single-line comments begin with //.
// This is a comment.
Everything after // on the current line is treated as a comment.
Multi-Line Comments
Multi-line comments begin with /* and end with */.
/*
This is a comment.
*/
Multi-line comments can span multiple lines.
Nested Comments
Unlike many programming languages, Swift supports nested multi-line comments.
/*
This is the start of the first comment.
/* This is a nested comment. */
This is the end of the first comment.
*/
Nested comments allow blocks of code that already contain comments to be commented out safely.
This is particularly useful when debugging or temporarily disabling sections of code.
Semicolons
Semicolons are optional in Swift.
Most Swift code places one statement per line and does not use semicolons.
let cat = "🐱"
print(cat)
Multiple Statements On One Line
Use a semicolon to separate multiple statements written on the same line.
let cat = "🐱"; print(cat)
In this example, the semicolon separates two statements.
Modern Swift Style
Modern Swift code rarely uses semicolons.
Writing one statement per line is generally preferred because it improves readability.
Integers
An integer is a whole number with no fractional component.
Examples include:
- 0
- -42
- 1024
Swift provides signed and unsigned integer types of different sizes.
Integer Bounds
Every integer type has a minimum and maximum value it can store.
Use the min and max properties to access these values.
print(UInt8.min)
0print(UInt8.max)
255A UInt8 value can store any number between 0 and 255.
Attempting to store a value outside the valid range results in an error.
Int
Int is Swift's default integer type.
Its size matches the native word size of the current platform.
Modern Apple platforms use a 64-bit architecture, so Int is typically a 64-bit integer.
In most situations, Int should be your preferred integer type.
UInt
UInt is Swift's default unsigned integer type.
Unsigned integers can store only positive values and zero.
let score: UInt = 100
Because UInt cannot represent negative values, assigning a negative number produces an error.
let score: UInt = -1 // Error
Swift recommends using Int unless you have a specific reason to use an unsigned integer type.
Floating-Point Numbers
Swift provides two floating-point types:
- Double
- Float
Double
Double is a 64-bit floating-point number.
It provides greater precision than Float.
Swift recommends using Double unless a specific reason exists to use Float.
Float
Float is a 32-bit floating-point number.
It uses less memory but stores fewer decimal digits of precision.
Type Safety and Type Inference
Swift is a type-safe language.
Type safety prevents values of incompatible types from being used together accidentally.
Type Inference
Swift can often determine a value's type automatically.
This process is known as type inference.
let meaningOfLife = 42
Swift infers that meaningOfLife is an Int.
let pi = 3.14159
Swift infers that pi is a Double.
Mixed Numeric Values
When integer and floating-point literals appear together, Swift infers a type that can represent both values.
let anotherPi = 3 + 0.14159
Swift infers that anotherPi is a Double.
Type inference reduces repetition while preserving type safety.
Numeric Literals
Numeric literals are values written directly in source code.
Decimal
17
Binary
0b10001
Octal
0o21
Hexadecimal
0x11
All four examples represent the decimal value 17.
Readable Numeric Literals
Underscores improve readability and are ignored by the compiler.
1_000_000
1_000.000_1
Numeric Type Conversion
Swift does not perform implicit numeric conversions between different numeric types.
Values must be converted explicitly.
Integer Conversion
Different integer types cannot be mixed automatically.
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
Integer and Floating-Point Conversion
Integers and floating-point values must also be converted explicitly.
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
Why Explicit Conversion Exists
Swift requires conversions to be visible in code so that changes in precision or range are never hidden.
Type Aliases
A type alias creates an alternative name for an existing type.
Use the typealias keyword.
typealias AudioSample = UInt16
Type aliases improve readability by expressing intent without creating a new type.
Booleans
Swift provides the Bool type for working with logical values.
A Boolean value can be either:
- true
- false
Conditional Statements
Conditional statements require a Boolean value.
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
Type Safety and Booleans
Unlike some languages, Swift requires actual Boolean values in conditional statements.
let i = 1
if i {
// Error
}
Integers are not automatically treated as Boolean values.
Tuples
Tuples group multiple values into a single compound value.
let http404Error = (404, "Not Found")
Decomposing Tuples
let (statusCode, statusMessage) = http404Error
Each value is assigned to a separate constant or variable.
Ignoring Values
Use an underscore (_) to ignore values that are not needed.
let (statusCode, _) = http404Error
Accessing Values by Position
http404Error.0
http404Error.1
Named Tuples
let http200Status = (
statusCode: 200,
description: "OK"
)
Named values can be accessed directly.
http200Status.statusCode
http200Status.description
Tuples provide a lightweight way to group related values together without creating a custom type.
Optionals
An optional represents a value that may be present or absent.
A non-optional value must always contain a value.
An optional can contain:
- A value
- nil
var serverResponseCode: Int? = 404
The question mark (?) indicates that the value is optional.
nil
Assign nil to indicate the absence of a value.
serverResponseCode = nil
Only optional values can be assigned nil.
Optional Binding
Optional binding safely extracts a value from an optional.
if let actualNumber = Int(possibleNumber) {
print("The string has an integer value of \(actualNumber)")
}
If the optional contains a value, the binding succeeds.
If it contains nil, the binding fails.
Multiple Optional Bindings
if let firstNumber = Int("4"),
let secondNumber = Int("42"),
firstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)")
}
Each condition must succeed before the body executes.
Providing a Fallback Value
Use the nil-coalescing operator (??) to provide a default value when an optional contains nil.
let displayName = name ?? "Guest"
If the optional contains a value, that value is used.
Otherwise, the fallback value is used.
Force Unwrapping
Force unwrapping accesses the value stored inside an optional.
Use an exclamation mark (!).
print(convertedNumber!)
Force unwrapping assumes that a value exists.
If the optional contains nil, the application terminates at runtime.
let name: String? = nil
print(name!) // Runtime error
Only use force unwrapping when you are certain a value exists.
Thinking About Force Unwrapping
Force unwrapping can be viewed as a shorthand way of saying:
A value must exist here.
print(name!)
Conceptually, this behaves similarly to:
if let name {
print(name)
} else {
fatalError("Expected name to contain a value.")
}
If the optional contains a value, execution continues normally.
If the optional contains nil, execution terminates with a runtime error.
Implicitly Unwrapped Optionals
An implicitly unwrapped optional is still an optional value.
Use an exclamation mark (!) in the type declaration.
let possibleString: String! = "An optional string."
Unlike a normal optional, Swift automatically force unwraps an implicitly unwrapped optional each time it is accessed.
This allows the value to be used without writing ! explicitly.
let assumedString: String = possibleString
Every access performs an implicit force unwrap.
If the value contains nil when it is accessed, a runtime error occurs.
Conceptually, every access behaves as though Swift had written:
possibleString!
Use implicitly unwrapped optionals only when a value may be nil initially but is guaranteed to contain a value before it is first accessed.
Error Handling
Error handling allows code to respond to recoverable failures at runtime.
Functions that can throw errors are marked with the throws keyword.
func makeASandwich() throws {
// ...
}
Use do-catch to handle errors.
do {
try makeASandwich()
} catch {
print("Failed to make sandwich.")
}
If an error is thrown, execution transfers to the matching catch block.
Assertions and Preconditions
Assertions and preconditions allow assumptions to be expressed directly in code.
If an assumption is violated, execution stops and reports the problem.
Assertions
Use assertions to detect programming mistakes during development.
assert(age >= 0, "A person\'s age cannot be less than zero.")
Assertions help identify bugs closer to their source.
Preconditions
Use preconditions when a requirement must be true before execution can continue safely.
precondition(index > 0, "Index must be greater than zero.")
Examples include:
- Valid array indexes
- Required input values
- Conditions that would make further execution unsafe
Assertions vs Preconditions
Use an assertion to detect mistakes during development.
Use a precondition to enforce requirements that must always be satisfied for the program to continue safely.



