5 exercises — optionals (guard let / if let), value vs reference types, retain cycles, opaque return types (some), and Swift Concurrency (actor, @MainActor).
0 / 10 completed
1 / 10
A Swift code review says: "Always use guard let at the top of a function instead of nested if let — it keeps the happy path unindented." What is the difference between guard let and if let for unwrapping optionals?
Swift optional unwrapping vocabulary:
Optional An optional (String?) is a value that is either a String or nil. Before using it, you must unwrap it.
if let — conditional binding
if let name = user.name {
print(name) // name is String here
}
// name not accessible outside
The bound constant (name) exists only inside the if block. Leads to "pyramid of doom" with multiple optionals.
guard let — early exit binding
guard let name = user.name else {
return // exit early if nil
}
print(name) // name is String for the rest of function
guard requires an exit (return, throw, break, continue, or fatalError()) in the else block. The bound constant is available after the guard statement — ideal for precondition checks.
Force unwrap ! user.name! — crashes with a runtime error if nil. Use only when you are 100% certain the value is non-nil (e.g., a static asset that must exist).
Optional chaining ?. user.address?.city — returns nil if any value in the chain is nil, rather than crashing.
Nil coalescing ?? user.name ?? "Anonymous" — provide a default value if nil.
Vocabulary: • optional — a value or nil; String? • unwrap — extract the value from an optional • golden path / happy path — the main logic flow with all conditions satisfied • pyramid of doom — deeply nested if let chains
2 / 10
An iOS code review says: "Use a struct here, not a class — this is a value type and it doesn't need identity semantics." What is the core difference between Swift structs (value types) and classes (reference types)?
Value type (struct) vs reference type (class) vocabulary:
Value type (struct, enum): When you assign or pass a value type, a copy is made: var a = Point(x: 1, y: 2)
var b = a
b.x = 10
print(a.x) // 1 — a is unaffected
Reference type (class): When you assign a reference type, both variables point to the same instance: let a = User(name: "Alice")
let b = a
b.name = "Bob"
print(a.name) // "Bob" — same instance
Which to use? Apple's guidance: prefer structs by default. Use classes when: • You need Objective-C interoperability • You need identity semantics (===) • The type has a lifecycle (delegate, view controller) • Reference semantics are intentional (shared mutable state is desired and controlled)
mutating keyword: Methods on a struct that modify its properties must be marked mutating. This signals that the caller's copy will be modified (or rather replaced with the modified copy).
Vocabulary: • value type — copied on assignment; struct, enum, tuple • reference type — shared on assignment; class, actor • identity (===) — checks if two references point to the same object instance • equality (==) — checks if two values are equal (Equatable protocol) • mutating — method on a struct that modifies the instance • copy-on-write (CoW) — Swift standard library types (Array, Dictionary) use CoW: actual copying happens lazily only when a mutation occurs
3 / 10
A code review leaves this note: "The closure should capture [weak self] here — otherwise it creates a retain cycle." What is a retain cycle and why does [weak self] fix it?
Closures, ARC, and retain cycles:
ARC (Automatic Reference Counting) Swift manages memory automatically via ARC. Each object has a retain count — ARC deallocates the object when the count reaches 0. A strong reference increments the retain count.
Retain cycle (memory leak): If Object A holds a strong reference to B, and B holds a strong reference to A — both retain counts stay ≥ 1, and neither is ever deallocated.
Common pattern in UIKit:
class ViewModel {
var onUpdate: (() -> Void)? // ViewModel owns the closure
}
class ViewController {
let vm = ViewModel()
func setup() {
vm.onUpdate = {
self.updateUI() // closure captures self strongly
// ViewController → ViewModel → closure → ViewController ♻️
}
}
}
Fix: capture list [weak self] vm.onUpdate = { [weak self] in
self?.updateUI() // self is now Optional; no cycle
} A weak reference does NOT increment the retain count. If the object is deallocated, the weak reference becomes nil.
[unowned self] — alternative: [unowned self] also avoids a retain cycle but does NOT become nil after deallocation. If the object is already deallocated and you access unowned self, it crashes. Use only when you are certain the object outlives the closure.
@escaping: A closure marked @escaping outlives the function that accepted it (stored, run later asynchronously). Escaping closures are where capture lists matter most.
Vocabulary: • ARC — Automatic Reference Counting; Swift's memory management model • retain count — number of strong references to an object • retain cycle — circular strong reference preventing deallocation (memory leak) • capture list — [weak x, unowned y] at the start of a closure • @escaping — closure that outlives its enclosing function • @noescape (default) — closure guaranteed to execute before function returns
4 / 10
A Swift PR description says: "Changed the return type from Animal to some Animal — an opaque return type." What does some mean and why is it useful?
Opaque types (some) and existential types (any):
some Protocol — opaque return type (Swift 5.1+) The function returns a specific, single concrete type that conforms to the protocol, but the caller doesn't see which. The compiler knows the concrete type and uses static dispatch (fast, optimisable).
Rule: all return paths must return the same concrete type.
func makeAnimal() -> some Animal {
return Dog() // always Dog; cannot return Cat on one path and Dog on another
}
SwiftUI example: var body: some View { Text("Hello") } The body is always a specific View type. SwiftUI uses this for performance — no dynamic dispatch needed.
any Protocol — existential type (Swift 5.7+) The function can return any conforming type — the concrete type is determined at runtime. Requires dynamic dispatch (slower). Swift 5.7 made any explicit to signal this cost.
func makeAnyAnimal() -> any Animal {
return Bool.random() ? Dog() : Cat() // different types on each call
}
Protocol — Swift's key abstraction: A protocol defines a contract (required methods and properties). Types conform to protocols; Swift uses structural typing — no inheritance required.
Protocol extension — add default implementations to a protocol; all conforming types inherit the default behavior.
Vocabulary: • protocol — defines required methods/properties; similar to interface in other languages • conformance — a type implementing all protocol requirements • opaque type (some) — caller-hidden concrete type; statically dispatched • existential (any) — runtime-determined concrete type; dynamically dispatched • protocol extension — default implementations for protocol requirements • associated type — a placeholder type in a protocol (like generics for protocols)
5 / 10
An iOS team migrates from GCD to Swift Concurrency. The PR description says: "Replaced DispatchQueue.main.async with await MainActor.run, and used an actor to protect the shared cache." What problem does actor solve?
Swift Concurrency vocabulary:
The data race problem When two threads read and write shared mutable state simultaneously without synchronisation, you get undefined behaviour. Traditional fix: DispatchQueue serial queues or NSLock.
Actor (Swift 5.5+) An actor is a reference type with automatic isolation — only one execution can access its mutable state at a time. No explicit locks needed; the compiler enforces isolation.
actor ImageCache {
private var cache: [String: UIImage] = [:]
func store(_ image: UIImage, for key: String) {
cache[key] = image // safe — only one caller at a time
}
func image(for key: String) -> UIImage? {
return cache[key]
}
}
Calling an actor from outside requires await: await imageCache.store(img, for: "avatar")
MainActor @MainActor is a global actor that ensures code runs on the main thread. Annotate a class, function, or property: @MainActor class ViewModel { ... } Replaces DispatchQueue.main.async with compile-time enforcement.
async/await • async func fetchData() -> Data — can suspend without blocking a thread • await data = fetchData() — suspends until the result is ready • Task { await ... } — creates a new concurrent task (unstructured) • async let a = fetch(); async let b = fetch(); let result = await (a, b) — parallel execution
Vocabulary: • actor — reference type with automatic serial access to mutable state • actor isolation — the property that mutable state cannot be accessed concurrently • @MainActor — global actor for UI / main-thread-only code • async/await — cooperative concurrency model (Swift 5.5+) • Task — a unit of async work; Task.detached for unstructured tasks • Sendable — a type safe to share across concurrency boundaries (no data races) • structured concurrency — async tasks follow a parent-child hierarchy; cancellation propagates
6 / 10
// In a Slack channel discussing API responses… Sarah: 'The server returned a 429 Too Many Requests error. We need to implement retry logic.' What does the HTTP status code 429 signify in this context, and what immediate action should be taken based on it?
The HTTP status code 429 (Too Many Requests) indicates that the server is temporarily unable to handle the request volume. This often happens due to rate limiting or a surge in traffic. Retrying the request within a short timeframe, respecting any retry-after headers provided by the server, is the correct immediate action. The other options misinterpret the code's meaning and suggest inappropriate responses.
7 / 10
// During a standup meeting… David: 'I finished implementing the new data validation logic for user registration.' What does 'data validation' typically involve in this scenario, and why is it important within the context of a mobile app's backend?
Data validation is the crucial process of verifying that data meets defined criteria before it's accepted and processed. In user registration, this means ensuring fields like email format, password strength, and required information are accurate and consistent. This prevents errors, maintains data integrity, and safeguards against malicious input – a critical element in securing mobile app backend systems.
8 / 10
// A code review comment… Reviewer: 'Consider using `enum` for this state management instead of a raw `Int`. It will improve type safety and readability.' What is the primary benefit of using an `enum` over a raw integer to represent a discrete set of states, and why does it enhance code maintainability?
The core benefit of using an `enum` is its enhanced type safety. An enum explicitly defines all possible states, preventing accidental assignment of invalid values which can lead to runtime errors. This dramatically improves code maintainability by providing clear documentation and reducing the likelihood of bugs. Using a raw integer offers no such guarantees.
9 / 10
// A PR description… Developer: 'Implemented a caching layer to reduce API calls.' What does the term 'caching' typically refer to in this context, and what is its primary goal within an application's architecture?
Caching involves storing copies of frequently accessed data (like API responses) locally within the application. The primary goal is to reduce latency and improve performance by serving this cached data instead of repeatedly making requests to the external API. This significantly reduces network traffic and improves response times – a common optimization technique.
10 / 10
// A code review comment… Reviewer: 'This class should be an `Observable` to allow other parts of the app to react to changes in its state.' What is an Observable pattern and how does it relate to this particular class's design?
The Observable pattern is a design approach where an object (the Observable) emits notifications when its state changes. Subscribers then react to these notifications, creating a loosely coupled system. In this scenario, making the class `Observable` allows other parts of the app – like UI elements – to automatically update themselves whenever the class's data changes. This promotes reactive programming and improves application responsiveness.
What does the "Swift Vocabulary" vocabulary exercise cover?
This exercise tests real IT vocabulary related to swift vocabulary through 10 multiple-choice questions, each built from realistic workplace sentences rather than abstract definitions.
Is this vocabulary exercise free to use?
Yes. Every exercise on CoderSlingo, including this one, is completely free — no account, sign-up, or payment required.
How many questions does this exercise have?
This exercise has 10 questions. Each one shows a real-world sentence or scenario with multiple-choice options and an explanation once you answer.
What happens after I answer a question?
You'll see immediate feedback showing whether your answer was correct, along with a short explanation of why — then a button to move to the next question, and a full results screen at the end.
Can I retry the exercise if I get questions wrong?
Yes. Once you reach the results screen, click "Try again" to reset your answers and go through the exercise from the start as many times as you like.
Do I need to create an account to take this exercise?
No account is needed. Your answers are scored in your browser during the session — nothing is saved to a server, so you can jump straight in.
Is my progress saved if I leave the page?
No — progress within an exercise resets if you navigate away or reload. Each exercise is short enough to complete in a few minutes in one sitting.
Are these vocabulary exercises connected to other topics?
Yes — browse the full vocabulary exercises hub to find related modules covering adjacent IT topics and roles.
How is this different from reading a glossary or blog article?
Exercises like this one are active recall drills — you have to choose the correct term or phrasing yourself, which builds retention faster than passively reading a definition.
Where can I find more vocabulary exercises?
Browse the full Vocabulary exercises hub for hundreds of modules covering Agile, DevOps, security, databases, architecture, and more — organised by IT role and skill.