Module 1: Swift Foundations
Swift Language Essentials
Swift is Apple's modern programming language for iPhone, iPad, Mac, Apple Watch and Apple TV apps. It is designed to be safe, fast and readable. SwiftUI, the framework you will use to build interfaces, leans heavily on Swift features such as structs, closures and protocols, so a solid grasp of the language makes everything else in this course easier.
Constants, variables and types
Use let for constants and var for values that change. Prefer let; the compiler will warn you when a var is never changed. Swift infers types, but every value has exactly one type and Swift will not silently convert between them.
let shopName = "Duka la Amani" // String
var itemsInBasket = 0 // Int
let price: Double = 349.99 // explicit type
itemsInBasket += 2
let total = Double(itemsInBasket) * price // convert Int to Double explicitly
print("Total: KES \(total)") // string interpolationString interpolation with \(...) inserts any value into text. The explicit Double(itemsInBasket) conversion is required: Swift refuses to multiply an Int by a Double directly, which prevents subtle rounding bugs.
Functions and closures
Functions use func. Parameters have argument labels that make calls read like sentences. You can use _ to omit a label, and give default values.
func formatPrice(_ amount: Double, currency: String = "KES") -> String {
let formatted = amount.formatted(.number.precision(.fractionLength(2)))
return "\(currency) \(formatted)"
}
formatPrice(1250) // "KES 1,250.00" (separator depends on locale)
formatPrice(9.5, currency: "USD") // "USD 9.50"A closure is a block of code you can pass around, like a function without a name. SwiftUI buttons, list sorting and network completion all use closures. When a closure is the last argument, you can write it after the parentheses, called trailing closure syntax.
let prices = [210.0, 180.0, 390.0, 95.0]
let expensive = prices.filter { $0 > 150 } // [210, 180, 390]
let withVat = prices.map { $0 * 1.16 } // hypothetical 16% rate
let sum = prices.reduce(0, +) // 875
let sorted = prices.sorted { $0 > $1 } // descending$0 and $1 are shorthand names for the closure's first and second parameters.
Structs, enums and protocols
A struct groups related values. Structs are value types: assigning one to another variable makes a copy. SwiftUI views and most app models are structs. A class is a reference type: variables share the same instance. Use structs by default and classes when you need shared, mutable identity.
struct Product {
let name: String
var price: Double
var stock: Int
var isAvailable: Bool { stock > 0 } // computed property
mutating func sell(_ quantity: Int) {
stock = max(0, stock - quantity)
}
}
enum PaymentMethod: String, CaseIterable {
case cash, card, mobileMoney
var label: String {
switch self {
case .cash: return "Cash"
case .card: return "Card"
case .mobileMoney: return "Mobile money"
}
}
}An enum lists a fixed set of cases. Swift's switch must handle every case, so if you add a new payment method later, the compiler points to every switch you need to update. A protocol describes requirements a type promises to meet; SwiftUI's View is a protocol, and Identifiable, Codable and Equatable are protocols you will use often.
Worked example: a small sales summary
struct Sale {
let product: String
let amount: Double
let method: PaymentMethod
}
let sales = [
Sale(product: "Rice 2kg", amount: 520, method: .mobileMoney),
Sale(product: "Milk 500ml", amount: 390, method: .cash),
Sale(product: "Bread", amount: 65, method: .mobileMoney)
]
let byMethod = Dictionary(grouping: sales, by: \.method)
for method in PaymentMethod.allCases {
let total = byMethod[method, default: []].reduce(0) { $0 + $1.amount }
print("\(method.label): KES \(total)")
}This groups sales by payment method and prints a total for each, including zero for card. CaseIterable gives allCases, and \.method is a key path pointing at a property. The default subscript [method, default: []] avoids dealing with a missing key.
Common mistakes to avoid
- Using var when let works. Follow the compiler's warnings.
- Mixing numeric types. Convert explicitly; do not fight the type system.
- Forgetting mutating. A struct method that changes properties needs the
mutatingkeyword. - Reaching for classes by habit. In Swift and SwiftUI, structs are the normal choice for data.
- Adding a default case to every switch. It hides missing cases when an enum grows. Handle cases explicitly when you can.
Exercise
Open a new Playground in Xcode (File, New, Playground). Define an enum ExpenseCategory with at least four cases and a label property, and a struct Expense with a title, amount and category. Create eight expenses, then use filter, map, reduce and Dictionary(grouping:by:) to print the total per category and the largest single expense.
Key points
- Use let by default; Swift never converts numeric types silently
- Closures with trailing syntax and $0 shorthand are everywhere in SwiftUI
- Structs are value types and the default choice; classes are reference types
- Enums with exhaustive switch statements catch missing cases at compile time