Swift Case Studies & Practical Application 4 — Questions and Answers
Question 1: You're refactoring a legacy codebase where many functions return `-1` to signal errors. Which modern Swift pattern replaces this anti-pattern?
- Returning `Int?` with nil for errors, or throwing a typed Error (Correct answer)
- Using a global error code variable
- Wrapping every call in a do-catch with forced try
- Replacing -1 with Int.min
Correct answer: Returning `Int?` with nil for errors, or throwing a typed Error
Optional returns (`Int?`) signal absence without sentinel values, and throwing functions with typed errors give callers structured error information — both are idiomatic replacements for magic-number conventions.
Question 2: A `ProductListViewModel` fetches data and your unit test must verify that `products` is populated after a successful network call. You mock the network layer. What is the key design requirement for this to work?
- The ViewModel must inherit from UIViewController
- The ViewModel must depend on a protocol, not a concrete network class (Correct answer)
- The network layer must use DispatchQueue.main
- The ViewModel must be a singleton
Correct answer: The ViewModel must depend on a protocol, not a concrete network class
If the ViewModel holds a protocol reference (e.g., `NetworkServiceProtocol`), tests can inject a `MockNetworkService` that returns canned data without real HTTP calls.
Question 3: Your Swift app parses untrusted JSON where a field might be a `String` or an `Int`. Using `Codable`, how do you handle this ambiguity?
- Declare the property as `Any` and skip Codable
- Write a custom `init(from:)` that tries decoding as String, then falls back to Int (Correct answer)
- Use `@dynamicMemberLookup` on the model
- Force-cast the decoded value in a post-init method
Correct answer: Write a custom `init(from:)` that tries decoding as String, then falls back to Int
A custom `init(from decoder:)` can attempt `container.decode(String.self, ...)` and catch the error to retry with `Int.self`, handling the type ambiguity gracefully.
Question 4: You have a Swift actor `DatabaseActor` with a method `func fetchUser(id: Int) async -> User`. On which thread does the body of `fetchUser` execute?
- Always the main thread
- On the actor's internal serial executor, isolated from other concurrent calls (Correct answer)
- A global concurrent thread pool like DispatchQueue.global()
- A new OS thread for every call
Correct answer: On the actor's internal serial executor, isolated from other concurrent calls
Actors serialize access through their own executor, so `fetchUser`'s body never runs concurrently with other methods on the same actor, preventing data races.
Question 5: A colleague writes `var items: [Item] = []` as a property of a SwiftUI `View` struct to hold fetched data. Why won't changes to `items` cause the view to re-render?
- Arrays are not supported in SwiftUI views
- Plain `var` properties don't participate in SwiftUI's state management; `@State` is needed (Correct answer)
- `[Item]` must conform to `Identifiable` first
- SwiftUI only observes `let` constants
Correct answer: Plain `var` properties don't participate in SwiftUI's state management; `@State` is needed
SwiftUI only re-renders a view when a property wrapped with `@State`, `@ObservedObject`, or similar triggers a change notification — plain `var` assignments are invisible to the framework.
Question 6: You need to ensure a `FileManager` operation runs on a background thread and its result is delivered on the main thread in Swift Concurrency. What is the correct structure?
- Call the method directly; Swift Concurrency is always on the main thread
- Run the operation in a `Task.detached` block or background task, then use `await MainActor.run { ... }` for UI updates (Correct answer)
- Use `DispatchQueue.global().async` then `DispatchQueue.main.async`
- Mark the function `@MainActor` and it will automatically background file I/O
Correct answer: Run the operation in a `Task.detached` block or background task, then use `await MainActor.run { ... }` for UI updates
Performing I/O off the main thread then calling `await MainActor.run` (or switching to a `@MainActor` context) is the Swift Concurrency equivalent of the classic GCD background-then-main pattern.
Question 7: A `CartViewModel` holds a `[CartItem]` and multiple views observe it. When `CartItem` is a struct, what happens to view state when you call `cart.items.remove(at: 0)`?
- Only the view that called remove() re-renders
- All views observing the `@Published items` property are notified and re-render (Correct answer)
- Nothing changes because structs are immutable
- A crash occurs because structs in arrays can't be removed
Correct answer: All views observing the `@Published items` property are notified and re-render
Mutating a `@Published` array property (even with struct elements) publishes the change through Combine, notifying every subscriber regardless of which view initiated the mutation.
You're refactoring a legacy codebase where many functions return `-1` to signal errors.
Which modern Swift pattern replaces this anti-pattern?