What Is Swift?
Swift is a modern programming language developed by Apple. It is used for iOS, macOS, watchOS, and tvOS app development, as well as server-side development. Its key features include a strong type system, null safety through optionals, and concise syntax.
This article covers Swift’s basic syntax through optional handling.
Variables and Constants
In Swift, let declares constants (immutable) and var declares variables (mutable). Type inference is powerful, so you rarely need to specify types explicitly.
import Foundation
// let — Constant (immutable, recommended)
let name = "John Doe" // Inferred as String
let age: Int = 25 // Explicit type declaration
let pi = 3.14159 // Inferred as Double
// name = "Jane Smith" // Compile error! let cannot be reassigned
// var — Variable (mutable)
var score = 85
score = 92 // Reassignment allowed
// String Interpolation
print("\(name) (age \(age)), score: \(score)")
// Output: John Doe (age 25), score: 92
// Multi-line string
let message = """
Hello,
Getting started with Swift.
Current score is \(score).
"""
print(message)
// Output:
// Hello,
// Getting started with Swift.
// Current score is 92.
// Collection types
let fruits = ["apple", "banana", "grape"] // Array
let scoreMap = ["math": 95, "english": 88] // Dictionary
let uniqueNums: Set = [1, 2, 3, 2, 1] // Set (duplicates removed)
print("Fruits: \(fruits)")
print("Math score: \(scoreMap["math"] ?? 0)")
print("Unique numbers: \(uniqueNums)")
// Output:
// Fruits: ["apple", "banana", "grape"]
// Math score: 95
// Unique numbers: [1, 2, 3]
In Swift, using let by default is recommended — only use var when the value needs to change.
Optionals
Optionals are a core concept in Swift. They represent situations where a value may or may not exist (nil) at the type level. Since non-optional types cannot be assigned nil, null reference errors are prevented at compile time.
import Foundation
// Optional declaration — Append ? after the type
var nickname: String? = "Johnny"
var phone: String? = nil // No value
// if let — Optional binding (safe unwrapping)
if let unwrapped = nickname {
print("Nickname: \(unwrapped)") // Executes only when non-nil
} else {
print("No nickname")
}
// Output: Nickname: Johnny
// guard let — Early return pattern
func greet(name: String?) {
guard let validName = name else {
print("No name provided.")
return // Return if nil
}
// After this point, validName is String (not optional)
print("Hello, \(validName)!")
}
greet(name: "Jane Smith")
// Output: Hello, Jane Smith!
greet(name: nil)
// Output: No name provided.
// Nil coalescing operator (??) — Provide default value
let displayName = nickname ?? "No name"
let displayPhone = phone ?? "No number"
print("Name: \(displayName), Phone: \(displayPhone)")
// Output: Name: Johnny, Phone: No number
// Optional chaining (?.) — Safe property/method access
let uppercased = nickname?.uppercased()
print("Uppercased: \(uppercased ?? "nil")")
// Output: Uppercased: JOHNNY
// map for optional transformation
let length: Int? = nickname.map { $0.count }
print("Nickname length: \(length ?? 0)")
// Output: Nickname length: 6
Force unwrapping (!) causes a runtime crash when the value is nil, so avoid it when possible. Use if let, guard let, and ?? together for safe handling.
Functions and Closures
Swift functions support argument labels, which improve readability at call sites.
import Foundation
// Function — Using argument labels
func calculateBMI(weight: Double, height: Double) -> Double {
return weight / (height * height)
}
// Separate external/internal parameter names
func greetUser(to name: String, with title: String = "") -> String {
return "Hello, \(name)\(title)!"
}
// Variadic parameters
func average(of numbers: Double...) -> Double {
guard !numbers.isEmpty else { return 0 }
return numbers.reduce(0, +) / Double(numbers.count)
}
print(calculateBMI(weight: 70, height: 1.75))
// Output: 22.857142857142858
print(greetUser(to: "John Doe"))
// Output: Hello, John Doe!
print(greetUser(to: "John Doe", with: " Ph.D."))
// Output: Hello, John Doe Ph.D.!
print(average(of: 85, 92, 78, 90))
// Output: 86.25
// Closures — First-class functions
let numbers = [5, 3, 8, 1, 9, 2, 7]
// Sorting — Using closures
let sorted = numbers.sorted { $0 < $1 } // Shorthand argument names
print("Sorted: \(sorted)")
// Output: Sorted: [1, 2, 3, 5, 7, 8, 9]
// map, filter, reduce chaining
let result = numbers
.filter { $0 > 3 } // Greater than 3
.map { $0 * 2 } // Double
.reduce(0, +) // Sum
print("Result: \(result)")
// Output: Result: 62
// Defining higher-order functions
func transform(_ items: [Int], using operation: (Int) -> Int) -> [Int] {
return items.map(operation)
}
let doubled = transform(numbers, using: { $0 * 2 })
print("Doubled: \(doubled)")
// Output: Doubled: [10, 6, 16, 2, 18, 4, 14]
Enumerations and Pattern Matching
Swift enums can have associated values, making them extremely powerful.
import Foundation
// Enum with associated values
enum NetworkResult {
case success(data: String, statusCode: Int)
case failure(error: String, statusCode: Int)
case loading
}
// Pattern matching — switch
func handleResult(_ result: NetworkResult) {
switch result {
case .success(let data, let code):
print("Success [\(code)]: \(data)")
case .failure(let error, let code) where code >= 500:
print("Server error [\(code)]: \(error)")
case .failure(let error, let code):
print("Client error [\(code)]: \(error)")
case .loading:
print("Loading...")
}
}
handleResult(.success(data: "User data", statusCode: 200))
// Output: Success [200]: User data
handleResult(.failure(error: "Server maintenance", statusCode: 503))
// Output: Server error [503]: Server maintenance
handleResult(.failure(error: "Auth failed", statusCode: 401))
// Output: Client error [401]: Auth failed
handleResult(.loading)
// Output: Loading...
// if case let — Extract a specific case
let results: [NetworkResult] = [
.success(data: "A", statusCode: 200),
.failure(error: "B", statusCode: 404),
.success(data: "C", statusCode: 201)
]
for case .success(let data, _) in results {
print("Success data: \(data)")
}
// Output:
// Success data: A
// Success data: C
Summary
Here is a summary of Swift’s key features.
- let/var: Distinguish between immutable and mutable for safer code. Use
letby default. - Optionals: Express nil possibility in the type with
?, and safely handle withif let,guard let, and??. - Argument labels: Provide near-natural-language readability at function call sites.
- Closures: Write concise functional code with first-class functions and shorthand argument names ($0, $1).
- Enumerations: Safely model states with associated values and pattern matching.
- Avoid force unwrapping (
!): Use safe unwrapping methods to prevent runtime crashes.