Swift Developer interview questions
100 real questions with model answers and explanations for iOS Developer candidates.
See a Swift Developer resume example →Practice with flashcards
Spaced repetition · Hunter Pass
Questions
let creates an immutable binding; var creates a binding that can change.
- Prefer let so accidental reassignment is a compiler error.
- Use var for a counter or total that must change.
- A let Array cannot append elements; a var Array can.
Why interviewers ask this: This checks the candidate's junior-level understanding of immutability.
Swift infers Int from the literal, so no annotation is needed.
- The inferred type is fixed at compile time.
- Write : Int64 when an API requires that exact type.
- A later incompatible assignment remains a compiler error.
Why interviewers ask this: This checks the candidate's junior-level understanding of static type inference.
Swift requires an explicit conversion because narrowing can lose information.
- Int(3.8) intentionally truncates the fractional part.
- Check range limits when input may be too large.
- Convert Int to Double for calculations needing fractions.
Why interviewers ask this: This checks the candidate's junior-level understanding of numeric type safety.
Value assignment creates an independent value; reference assignment shares one instance.
- Struct, enum, Array, and Dictionary use value semantics.
- Class instances have shared reference semantics.
- Changing one struct copy does not change another copy.
Why interviewers ask this: This checks the candidate's junior-level understanding of value and reference behavior.
Array copies can share storage until one copy is mutated.
- Assignment usually avoids an immediate element-by-element copy.
- The first mutation creates private storage for that copy.
- Observable behavior still follows value semantics.
Why interviewers ask this: This checks the candidate's junior-level understanding of copy-on-write.
An Optional holds either a wrapped value or nil.
- Int? is shorthand for Optional<Int>.
- It must be unwrapped where a plain Int is required.
- It models missing data without sentinel values such as -1.
Why interviewers ask this: This checks the candidate's junior-level understanding of optional values.
if let enters its branch only when the optional contains a value.
- nil makes the condition fail without a crash.
- The bound name is non-optional inside the branch.
- else handles the missing-value path explicitly.
Why interviewers ask this: This checks the candidate's junior-level understanding of optional binding.
guard let suits a precondition whose failure should exit early.
- Its else block must return, throw, break, or continue.
- The unwrapped value remains available after guard.
- It keeps the successful path from becoming deeply nested.
Why interviewers ask this: This checks the candidate's junior-level understanding of optional control flow.
String uses String.Index because one Character may contain several Unicode scalars.
- startIndex identifies the first valid character boundary.
- index(after:) advances to another valid boundary.
- Array(string) is simpler for tiny tasks but allocates storage.
Why interviewers ask this: This checks the candidate's junior-level understanding of Unicode-safe strings.
Array is ordered, Set is unique, and Dictionary maps keys to values.
- Array allows duplicates and position-based access.
- Set suits fast membership checks when order is irrelevant.
- Dictionary lookup returns an optional because a key may be absent.
Why interviewers ask this: This checks the candidate's junior-level understanding of collection choice.
A tuple groups a fixed set of related values without a new named type.
- Named fields make (code: 200, message: "OK") readable.
- A function can return two small results in one tuple.
- Use a struct when data needs methods or broad reuse.
Why interviewers ask this: This checks the candidate's junior-level understanding of tuples.
a...b includes b, while a..<b excludes b.
- 1...3 produces 1, 2, and 3.
- 0..<array.count matches ordinary integer positions.
- Iterate elements directly when no index is needed.
Why interviewers ask this: This checks the candidate's junior-level understanding of range boundaries.
A function can return a named tuple for a small one-off result.
- A return type may be (min: Int, max: Int).
- Callers read result.min and result.max.
- Use a struct when the result becomes a domain model.
Why interviewers ask this: This checks the candidate's junior-level understanding of function return values.
Argument labels describe parameters at the call site.
- move(from: 1, to: 3) reads like a sentence.
- The internal parameter name can differ from its label.
- Use _ only when omitting a label stays clear.
Why interviewers ask this: This checks the candidate's junior-level understanding of argument labels.
A default lets callers omit an optional argument while sharing one implementation.
- greet(name:punctuation:) can default punctuation to "!".
- An explicit argument overrides the default.
- Required business input should not be hidden behind a default.
Why interviewers ask this: This checks the candidate's junior-level understanding of default parameters.
inout lets a function modify a variable supplied by its caller.
- The declaration places inout before the parameter type.
- The call uses &, as in increment(&count).
- A let constant cannot be passed because mutation is required.
Why interviewers ask this: This checks the candidate's junior-level understanding of inout mutation.
A closure is executable code that can be stored and passed as a value.
- It may capture names from its surrounding scope.
- map and filter accept closures.
- Trailing syntax moves a final closure outside parentheses.
Why interviewers ask this: This checks the candidate's junior-level understanding of closure basics.
@escaping means a parameter closure may outlive the function call.
- Stored completion handlers commonly need @escaping.
- A nonescaping closure finishes during the call.
- An escaping closure uses explicit self when capturing an instance.
Why interviewers ask this: This checks the candidate's junior-level understanding of escaping closures.
Raw values give every case one fixed value of a shared primitive type.
- A Direction: String enum can expose string raw values.
- init(rawValue:) is failable because input may not match.
- The raw value is declared once, not supplied per instance.
Why interviewers ask this: This checks the candidate's junior-level understanding of enum raw values.
Associated values attach runtime data to a particular enum case.
- Cases may carry different types, such as success(Data).
- A switch pattern extracts the attached value.
- Raw values are fixed, while associated values vary per instance.
Why interviewers ask this: This checks the candidate's junior-level understanding of associated values.
Locked questions
- 21
When would you choose a struct over a class?
swiftvalue-typesreference-types - 22
How do stored and computed properties differ?
- 23
What are willSet and didSet?
- 24
Why must a struct method sometimes be mutating?
swiftvalue-typesmutation - 25
What is an initializer responsible for?
- 26
What does a protocol define?
typingprotocols - 27
What can an extension add?
extensions - 28
Why use a generic function instead of Any?
generics - 29
How do throws, try, and do-catch work together?
error-handling - 30
When is Result useful?
result-type - 31
What does defer do?
resource-cleanup - 32
What does ARC manage?
memory - 33
How do weak and unowned differ?
memorymemory-management - 34
What does Codable provide?
codableserialization - 35
How do CodingKeys help with JSON?
serialization - 36
What do URL, Data, and Date represent in Foundation?
- 37
How do private, fileprivate, internal, and public differ?
- 38
What is a Swift module and what does import do?
swiftmodules - 39
What are package, target, and product in SPM?
swift-package-manager - 40
What do async and await mean?
asyncconcurrency - 41
What is Task used for?
structured-concurrency - 42
What does @MainActor guarantee?
actor-isolation - 43
What problem does an actor solve?
concurrency - 44
What does Sendable express?
concurrency - 45
What is the basic structure of an XCTest test?
xctestswiftvalue-types - 46
What are setUp and tearDown for?
- 47
What is the boundary between a SwiftUI View and state?
swiftuiswift - 48
How do SwiftUI and UIKit differ?
uikitswiftuiswift - 49
How can a Swift CLI read process arguments?
concurrencyswift - 50
What does a simple Vapor route do?
server-side - 51
Int("abc") returns nil. How should a CLI report invalid input?
- 52
A force unwrap crashes when a JSON field is absent. What should change?
- 53
A missing nickname must display "Guest". Which optional expression fits?
swiftoptionals - 54
Decoding reports keyNotFound for a sometimes absent field. How do you fix the model?
- 55
JSON has "age": "20", but the model uses Int. Why does decoding fail?
- 56
JSON uses user_id while Swift uses userID. What fixes keyNotFound locally?
swift - 57
Removing Array elements while traversing old indices crashes. How do you rewrite it?
- 58
counts[word] += 1 does not compile for a Dictionary. Why?
- 59
After var b = a, appending to Array b leaves a unchanged. Is that expected?
- 60
Changing b.name also changes a.name after let b = a for a class. Why?
reference-types - 61
text[0] gives a compiler error. How do you read the first Character?
- 62
A stored closure prints the latest counter, not its creation-time value. How do you capture a snapshot?
closuressnapshot - 63
An @escaping callback requires explicit self for a property. What does the compiler want?
callbacksescaping-closures - 64
A controller never deinitializes after storing a closure that uses self. What is likely wrong?
closures - 65
A [weak self] callback finds self nil when it runs. Is that necessarily a bug?
callbacksmemory - 66
A type misses a protocol get-set property requirement. What must it provide?
typingprotocols - 67
Protocol Resettable requires mutating func reset(), but a struct's reset gets 'self is immutable' at count = 0. What fixes it?
immutabilitytypingswift - 68
A generic maximum cannot use > on unconstrained T. What is missing?
generics - 69
readFile() says the throwing call is not marked with try. What are the choices?
- 70
A general catch hides a known invalidInput case. How do you preserve its message?
- 71
A function prints an error, then its caller continues as if work succeeded. What should change?
- 72
A file handle stays open when parsing throws. What guarantees cleanup?
error-handling - 73
An async call says it is not marked with await. What is required?
asyncconcurrency - 74
A synchronous button callback must call async load(). What is the small boundary fix?
asynccallbacksconcurrency - 75
Cancelling a Task does not stop its long loop. What is missing?
structured-concurrency - 76
Two tasks increment a counter, but the final value is too small. How can an actor help?
concurrency - 77
Reading counter.value outside an actor gives an isolation error. What should the caller do?
concurrency - 78
Async work updates UI state and triggers an actor warning. How do you fix it?
asyncconcurrencystate - 79
Capturing a mutable class in a @Sendable closure warns. What is a beginner-safe redesign?
closuresconcurrencyreference-types - 80
Two independent async fetches run sequentially. How can both start before awaiting?
asyncconcurrency - 81
An XCTest needs a value from async loadName(). What signature works?
asyncconcurrencytesting - 82
parse("bad") must throw. How should XCTest verify it?
xctest - 83
A test passes alone but fails after another test mutates a singleton. What is the first repair?
- 84
SPM says no such module Utility although the target exists. What should you inspect first?
swift-package-managermodules - 85
A product is ToolsKit, but its module is ToolsCore. Which name belongs in import?
modules - 86
SPM expects AppCLI sources under Sources/AppCLI. What are two valid fixes?
swift-package-manager - 87
FileManager cannot find config.json from a CLI. How do you debug the path?
configfile-system - 88
A JSON CLI prints only "decode failed". How do you expose the useful cause?
- 89
A CLI crashes on CommandLine.arguments[1] with no arguments. What is the minimal fix?
- 90
ArgumentParser requires --input, but the user omits it. What should happen?
argument-parser - 91
ArgumentParser receives --count many for Int. Where should failure happen?
argument-parser - 92
GET /users returns 404, but Vapor registered app.post. What is wrong?
server-side - 93
The Vapor route /users/:id matches /users/abc, but the handler needs an Int id. Which response and fix are correct?
server-side - 94
A Vapor POST receives malformed JSON for Content. What should the handler do?
server-side - 95
A Vapor request accepts an empty username and fails later. Where should validation occur?
validationserver-side - 96
A Vapor lookup returns nil for user 42. Which status beats an empty 200?
server-side - 97
A Vapor async handler calls a throwing service without try await. What is needed?
asyncconcurrencyserver-side - 98
A SwiftUI button changes a local var in body, but text never updates. What is needed?
swiftuiswift - 99
A SwiftUI List loses rows because items share an id. What must change?
swiftuiswift - 100
A reused UITableViewCell briefly shows the previous row's asynchronously loaded image. How do you fix it?
asyncconcurrencyuikit