Swift
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Optionals
-
Section 4: Object-Oriented and Value Types
-
Section 5: Memory Management
-
Section 6: Generics and Error Handling
-
Section 7: Concurrency
-
Section 8: Working with Collections
-
Section 9: Codable and Data Handling
-
Section 10: Protocol-Oriented Programming
-
Section 11: Testing and Tooling
-
Section 12: Practical Projects
-
Section 13: Interview Practice
-
Section 14: More Practice Exercises
-
Section 15: More Standard Library
-
Section 16: Advanced Concurrency
-
Section 17: Foundation Framework Deep Dive
-
Section 18: URLSession and Networking Deep Dive
-
Section 19: Combine Framework
-
Section 20: SwiftUI Fundamentals for Swift Developers
-
Section 21: Server-Side Swift with Vapor
-
Section 22: Swift Package Manager Deep Dive
-
Section 23: Swift Concurrency Deep Dive
-
Section 24: More Language Features
-
Section 25: Error Handling Deep Dive
-
Section 26: Testing Deep Dive
-
Section 27: Data Structures and Algorithms in Swift
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Swift Macros (Swift 5.9+)
-
Section 31: Property Wrappers Ecosystem
-
Section 32: Swift Interop Deep Dive
-
Section 33: iOS App Architecture Patterns
-
Section 34: Performance and Debugging
-
Section 35: App Distribution and CI/CD
-
Section 36: More Practical Projects
-
Section 37: SwiftData and Persistence
-
Section 38: More Design Patterns
-
Section 39: More Review and Practice
-
Section 40: More Foundation Deep Dive
-
Section 41: Advanced Collections in Swift
-
Section 42: Advanced Generics Practice
-
Section 43: UIKit for Legacy and Hybrid Apps
-
Section 44: watchOS and visionOS Development Basics
-
Section 45: More Networking Patterns
-
Section 46: More Testing Practice
-
Section 47: Accessibility in Swift Apps
-
Section 48: Localization
-
Section 49: More Practical Projects Round 2
-
Section 50: Swift Charts Framework
-
Section 51: More Interview and Algorithm Practice
-
Section 52: Final Practice and Mastery
-
Section 53: Swift Compiler and Build System
-
Section 54: More Concurrency Practice
-
Section 55: App Store Guidelines and Review
-
Section 56: More Design and Architecture
4: Variables and Constants
A few years ago, I was reviewing a pull request for a checkout system. A junior developer had declared the transactionID as a variable using var. It seemed harmless at first, but about 200 lines deeper in a complex loop, there was a logic error that accidentally reassigned that ID. The code compiled perfectly, but in production, it started updating the wrong orders in the database. It was a nightmare to debug. If that ID had been declared as a constant, the compiler would have caught the mistake instantly, throwing an error the moment the developer tried to change it. That's why I always tell people: start with a constant, and only move to a variable when the compiler forces your hand.
Locking data down with let
In Swift, when you know a value isn't going to change after you first set it, you use let. We call this a constant. It's not just a stylistic choice; it's a performance optimization and a safety feature. When you use let, you're telling the Swift compiler, "I promise this value will stay exactly like this for the rest of its life."
let apiKey = "abc123xyz789"
let maximumLoginAttempts = 5
If you try to write apiKey = "new_key" later in your code, Swift will stop you dead in your tracks. Personally, I treat let as my default. If I'm creating a piece of data, I start with let. If I later realize I need to update that value, I'll change it to var. It's much easier to change a constant to a variable than it is to hunt down where a variable is being accidentally changed.
Handling change with var
Of course, some things have to change. A user's current score in a game, the text in a search bar, or the remaining battery percentage of a device—these are all dynamic. For these, we use var to declare a variable.
var currentScore = 0
var userBio = "Just a coffee lover and coder."
// This is perfectly fine
currentScore += 10
userBio = "Coffee lover, coder, and now a Swift learner!"
The danger with var is that it opens the door to "side effects." If you pass a variable into five different functions, any one of those functions could potentially change the value, leaving you wondering why your data is suddenly wrong. Keep your var usage lean and purposeful.
Letting Swift guess the type
You might have noticed that in my examples, I didn't explicitly tell Swift that currentScore is an Integer or that userBio is a String. This is called Type Inference. Swift is smart enough to look at the value you provide—like 0 or "Hello"—and figure out the type on its own.
You can be explicit if you want to be, which looks like this:
let pi: Double = 3.14159
var playerName: String = "Player One"
I usually only do this if I'm declaring a variable without giving it an initial value immediately, or if I want to ensure a number is treated as a specific type (like a Double instead of an Int). Otherwise, let the compiler do the heavy lifting for you.
📋 Practical Task
Building a Mutable User Profile
Imagine you are building the settings page for a social media app. Some user information should never change (like their unique account ID), while other information is updated frequently.
Write a small Swift script that does the following:
- Create a constant for the
accountID(e.g., "USER_9921"). - Create a constant for the
joinDate(e.g., "October 2023"). - Create a variable for the
displayName(e.g., "SwiftNewbie"). - Create a variable for the
followerCount(start it at 0).
After declaring these, simulate the user updating their profile by changing the displayName to something new and incrementing the followerCount by 1. Finally, try to change the accountID to a new value and observe the compiler error that occurs.
There are no comments for now.