Skip to main content
    Courses/Swift/Variables and Data Types

    Lesson 2 • Beginner

    Variables and Data Types 📦

    By the end of this lesson you'll store text, numbers, and true/false values in Swift, choose let or var correctly, and handle missing values safely with optionals — the bedrock of every Swift program.

    What You'll Learn in This Lesson

    • • Declare values with var (mutable) and let (constant) — and why to prefer let
    • • Let Swift infer types, or write explicit annotations like : Int
    • • Use the core types: Int, Double, String, Bool
    • • Build clean text with string interpolation \\(name)
    • • Represent "maybe no value" with optionals (Int?, nil)
    • • Unwrap optionals safely with if let and ??, and know why ! is risky

    📊 The Core Data Types

    TypeHoldsExampleWhen to use
    IntWhole numberslet age = 25Counts, ages, indexes
    DoubleDecimal numberslet h = 1.75Measurements, money, averages
    StringTextlet name = "Al"Names, messages, input
    Booltrue / falselet ok = trueYes/no decisions
    Int?An Int or nilvar n: Int? = nilA value that might be missing

    Text always uses "double quotes". A ? after any type (like Int?) makes it optional — it can also hold nil.

    1️⃣ var vs let — Mutable or Constant

    Every value you name is either a variable or a constant. Use var when the value will change, and let when it won't. The golden rule in Swift is prefer let: it documents that the value is fixed, prevents accidental changes, and helps the compiler optimise. Read this worked example, run it, then you'll write your own.

    Worked example: var vs let
    // A variable is a named box that stores a value. Swift gives you two kinds.
    
    // 'var' makes a MUTABLE box — you can change what's inside later.
    var score = 10
    score = 25            // ✅ fine: score is a var
    print("score = \(score)")   // score = 25
    
    // 'let' makes a CONSTANT — it's set once and can NEVER change.
    let pi = 3.14159
    print("pi = \(pi)")         // pi = 3.14159
    // pi = 3.2            // ❌ compile error if you uncomment this
    
    // Rule of thumb: reach for 'let' first. Only switch to 'var' when you
    // actually need the value to change. Swift even warns you if a 'var'
    // is never mutated — a nudge to use 'let'.
    let appName = "Weatherly"
    var loginCount = 0
    loginCount = loginCount + 1   // this one really does change
    print("\(appName) opened \(loginCount) time(s)")
    Output
    score = 25
    pi = 3.14159
    Weatherly opened 1 time(s)
    This is real code — run it for free atSwiftFiddleor in your own editor.

    2️⃣ Types: Inference vs Annotations

    Swift is statically typed — every value has one fixed type the compiler knows in advance. Usually you don't write the type: type inference reads the value and picks it for you. When there's no starting value, or you want a specific type, add an explicit annotation with : Type. Remember that Int and Double never mix automatically — convert on purpose with Double(...) or Int(...).

    Worked example: inference, annotations, and number conversion
    // TYPE INFERENCE: Swift reads the value and figures out the type for you.
    let age = 25          // inferred as Int    (whole number)
    let height = 1.75     // inferred as Double (decimal number)
    let name = "Alice"    // inferred as String (text, in "double quotes")
    let isOnline = true   // inferred as Bool   (true or false)
    
    // EXPLICIT ANNOTATION: you write ": Type" yourself. Useful when there is
    // no starting value yet, or when you want a specific type.
    let count: Int = 0
    let ratio: Double = 2        // store 2 as a Double, not an Int
    var nickname: String = "Al"
    var isReady: Bool = false
    
    print("\(name) is \(age), height \(height)m, online: \(isOnline)")
    print("count=\(count) ratio=\(ratio) nickname=\(nickname) ready=\(isReady)")
    
    // Int holds whole numbers; Double holds decimals. They are different types,
    // so Swift will NOT mix them automatically — you must convert on purpose.
    let apples = 3        // Int
    let pricePer = 0.5    // Double
    let total = Double(apples) * pricePer   // convert Int -> Double, then multiply
    print("total = \(total)")              // total = 1.5
    Output
    Alice is 25, height 1.75m, online: true
    count=0 ratio=2.0 nickname=Al ready=false
    total = 1.5
    This is real code — run it for free atSwiftFiddleor in your own editor.

    Your turn. The program below is almost complete — fill in the three blanks marked ___ using the hints, then run it and check the output.

    🎯 YOUR TURN: declare three constants
    // 🎯 YOUR TURN — replace each ___ then run it in SwiftFiddle.
    
    // 1) Make a constant 'city' set to a city name (text in "double quotes")
    let city = ___          // 👉 e.g. "London"
    
    // 2) Make a constant 'year' set to a whole number
    let year = ___          // 👉 e.g. 2026 (an Int — no decimal point)
    
    // 3) Make a constant 'temperature' set to a decimal number
    let temperature = ___   // 👉 e.g. 18.5 (a Double)
    
    // This line already works once your three constants exist:
    print("In \(city) in \(year) it was \(temperature)°C")
    
    // ✅ Expected output (example):
    //    In London in 2026 it was 18.5°C
    This is real code — run it for free atSwiftFiddleor in your own editor.

    3️⃣ String Interpolation

    String interpolation lets you drop a value straight into text using \\(...) — the backslash, then your value in parentheses. It reads far better than joining pieces with +, and you can even run a small calculation inside the parentheses.

    Worked example: string interpolation
    // String interpolation drops a value straight into text using \(...).
    let userName = "Sam"
    let messages = 5
    
    // Everything inside \(...) is replaced with the value.
    print("Hi \(userName), you have \(messages) new messages.")
    
    // You can run real code inside the parentheses, not just a name:
    let price = 4.0
    let qty = 3
    print("\(qty) coffees cost £\(price * Double(qty))")   // 3 coffees cost £12.0
    
    // Build up longer strings the same way — it reads far better than gluing
    // pieces together with '+'.
    let first = "Ada"
    let last = "Lovelace"
    print("Full name: \(first) \(last)")   // Full name: Ada Lovelace
    Output
    Hi Sam, you have 5 new messages.
    3 coffees cost £12.0
    Full name: Ada Lovelace
    This is real code — run it for free atSwiftFiddleor in your own editor.

    4️⃣ Optionals — Handling Missing Values

    Optionals are Swift's standout safety feature. An optional type (written with ?, e.g. Int?) holds either a value or nil — Swift's word for "nothing here". Because "might be missing" is part of the type, the compiler forces you to deal with the empty case, which eliminates the null-crash bugs that plague other languages. You must unwrap an optional before using it: the safe ways are optional binding (if let) and nil-coalescing (??). Force-unwrapping with ! skips the check and crashes on nil, so use it rarely.

    Worked example: nil, if let, ??, and force-unwrap
    // An OPTIONAL means "a value, OR nothing (nil)". You write it with a ? .
    // nil is Swift's word for "no value here yet".
    var middleName: String? = nil      // might hold a String, currently holds nothing
    middleName = "Quinn"               // now it has a value
    
    // Optionals appear naturally: Int("...") may fail, so it returns Int?.
    let good = Int("42")     // Optional(42)  — the conversion worked
    let bad = Int("hello")   // nil           — "hello" is not a number
    
    // You can't use an optional directly — you must UNWRAP it first.
    
    // Safest unwrap: optional binding with 'if let'. It runs the block ONLY
    // when a value is present, giving you a plain (non-optional) constant.
    if let number = good {
        print("Parsed a number: \(number)")   // runs: Parsed a number: 42
    } else {
        print("That wasn't a number")
    }
    
    if let number = bad {
        print("Parsed a number: \(number)")
    } else {
        print("That wasn't a number")          // runs: That wasn't a number
    }
    
    // Nil-coalescing '??' supplies a default when the optional is nil.
    let typed: String? = nil
    let display = typed ?? "Guest"             // use "Guest" because typed is nil
    print("Welcome, \(display)!")             // Welcome, Guest!
    
    // Force-unwrap with '!' grabs the value WITHOUT checking. If it's nil your
    // program CRASHES. Only use it when you are 100% certain a value exists.
    let definitely = Int("7")!                 // safe here — "7" is clearly a number
    print("Force-unwrapped: \(definitely)")   // Force-unwrapped: 7
    Output
    Parsed a number: 42
    That wasn't a number
    Welcome, Guest!
    Force-unwrapped: 7
    This is real code — run it for free atSwiftFiddleor in your own editor.

    Now you try. Fill in the two blanks to handle values that might be missing — one with ??, one with if let.

    🎯 YOUR TURN: unwrap safely
    // 🎯 YOUR TURN — handle a value that might be missing.
    
    // favouriteColour is an optional String that is currently nil.
    let favouriteColour: String? = nil
    
    // 1) Use nil-coalescing to fall back to "unknown" when it's nil.
    let shown = favouriteColour ___ "unknown"   // 👉 replace ___ with the ?? operator
    print("Favourite colour: \(shown)")
    
    // 2) Int("twelve") can't be parsed, so it is nil. Safely unwrap it with
    //    optional binding, printing the number OR a friendly message.
    let parsed = Int("twelve")
    if ___ value = parsed {                     // 👉 replace ___ with the keyword 'let'
        print("Got the number \(value)")
    } else {
        print("Not a valid number")
    }
    
    // ✅ Expected output:
    //    Favourite colour: unknown
    //    Not a valid number
    This is real code — run it for free atSwiftFiddleor in your own editor.

    Pro Tips

    • 💡 Default to let. Start every value as a constant; only change it to var if the compiler tells you it must change.
    • 💡 Avoid ! on real data. Anything that came from a user, a file, or a conversion can be nil — reach for if let or ?? instead.
    • 💡 Convert numbers explicitly. Wrap with Double(x) or Int(x) when mixing Int and Double.
    • 💡 Name things well. loginCount tells a story; x doesn't.

    Common Errors (and the fix)

    • "Fatal error: Unexpectedly found nil while unwrapping an Optional value" — you force-unwrapped with ! on something that was nil, which crashes. Use if let or ?? to handle the empty case safely.
    • "Cannot assign to value: 'pi' is a 'let' constant" — you tried to change a let. Either keep it constant, or declare it with var if it really needs to change.
    • "Binary operator '*' cannot be applied to operands of type 'Int' and 'Double'" — you mixed number types. Convert first: Double(apples) * price.
    • "Value of optional type 'Int?' must be unwrapped" — you used an optional directly. Unwrap it first with if let, or provide a default with ??.

    📋 Quick Reference

    TaskCodeResult
    Constantlet pi = 3.14can't change
    Variablevar n = 0can change
    Annotationlet c: Int = 0explicit type
    Interpolate"Hi \\(name)"Hi Sam
    Optionalvar x: Int? = nilvalue or nil
    Safe unwrapif let v = x { … }runs if not nil
    Defaultx ?? 00 when nil
    ConvertDouble(myInt)Int → Double

    Frequently Asked Questions

    Q: Should I use var or let?

    Prefer let. Use let for any value that never changes after you set it — it makes your intent clear and lets the compiler catch accidental changes. Only switch to var when the value genuinely needs to change (a counter, a running total). Swift even warns you when a var is never modified, suggesting you change it to let.

    Q: What is an optional in Swift?

    An optional is a type that holds either a value or nothing (nil). You write it by adding ? to a type, like Int? or String?. Optionals make 'might be missing' explicit in the type system, so the compiler forces you to handle the empty case. This eliminates the null-pointer crashes common in other languages.

    Q: What does the ! force-unwrap operator do, and why is it dangerous?

    Putting ! after an optional unwraps it without checking, giving you the plain value. If the optional is nil at that moment, your program crashes immediately ('Unexpectedly found nil while unwrapping an Optional value'). Prefer if let or the ?? operator, which handle nil safely. Only force-unwrap when you are certain a value exists.

    Q: Why won't Swift let me add an Int and a Double together?

    Int (whole numbers) and Double (decimals) are different types, and Swift never converts between number types automatically — that prevents silent precision bugs. Convert explicitly: write Double(myInt) to turn an Int into a Double, or Int(myDouble) to go the other way (which drops the decimal part).

    Q: When do I need to write the type, like : Int?

    Type inference covers most cases — Swift reads the value and picks the type for you. You write an explicit annotation when there is no starting value (var name: String?), when you want a specific type that differs from the inferred one (let ratio: Double = 2), or to document intent for the next reader.

    Mini-Challenge: Profile Line

    No blanks this time — just a brief and an outline. Build it, run it, and check your output against the example in the comments. This is exactly the kind of small program real apps are made of.

    🎯 MINI-CHALLENGE: build a profile line
    // 🎯 MINI-CHALLENGE: Profile line
    // 1. Make a 'let' constant 'name' (a String) with your name.
    // 2. Make a 'var' 'age' (an Int) with your age, then add 1 to it
    //    (it's your birthday!) using:  age = age + 1
    // 3. Make an OPTIONAL 'nickname' of type String? — set it to nil.
    // 4. Use ?? to choose the nickname, or "no nickname" when it's nil.
    // 5. Print one tidy line using \(...) interpolation, e.g.:
    //      "Sam is now 21, also known as no nickname"
    //
    // ✅ Example output (name=Sam, age was 20, nickname=nil):
    //    Sam is now 21, also known as no nickname
    
    // your code here
    This is real code — run it for free atSwiftFiddleor in your own editor.

    🎉 Lesson Complete!

    • let = constant (prefer this), var = mutable
    • ✅ Type inference usually picks the type; add : Int-style annotations when needed
    • ✅ Core types: Int, Double, String, Bool — convert numbers with Double(...)/Int(...)
    • ✅ Build text cleanly with interpolation \\(value)
    • ✅ Optionals (Int?) hold a value or nil; unwrap with if let or ??, and avoid !
    • Next lesson: Control Flow — make decisions with if and repeat work with loops

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service