iOS Interview Questions & Answers
This set covers 88 iOS interview questions with point-wise answers, written from a working iOS developer's point of view. Each answer is short, focused, and structured the way you should actually speak in an interview.
Swift Language Fundamentals
1. What is the difference between let and var in Swift?
letdeclares a constant — its value cannot be reassigned after initialisation.vardeclares a variable that can be changed later.- Prefer
letby default; it makes intent clear and lets the compiler optimise and catch accidental mutation. - For reference types,
letonly fixes the reference, not the object's internal mutable state.
2. What are optionals and why does Swift use them?
- An optional (
T?) represents a value that may be present or absent (nil). - They make the absence of a value explicit in the type system, eliminating null-pointer surprises.
- You must unwrap an optional before using it, forcing you to handle the
nilcase. - Under the hood it is an enum with
.some(value)and.nonecases.
3. What are the safe ways to unwrap an optional?
if let/guard letfor conditional binding.- Nil-coalescing
??to provide a default value. - Optional chaining
obj?.propertyto short-circuit safely. - Avoid force unwrap
!unless you can guarantee the value is non-nil.
4. What is the difference between if let and guard let?
if letcreates a scope where the unwrapped value is valid only inside the braces.guard letunwraps and keeps the value available for the rest of the function, exiting early onnil.guardimproves readability by handling failure first and avoiding deep nesting.- Use
guardfor preconditions; useif letfor optional, localised branches.
5. What is the difference between value types and reference types?
- Value types (struct, enum, tuple) are copied on assignment — each variable owns its data.
- Reference types (class, closure) share a single instance via a pointer.
- Value types reduce shared mutable state and are thread-safer by default.
- Swift favours structs; use classes only when identity, inheritance, or shared state is needed.
6. Why are structs preferred over classes in Swift?
- Value semantics avoid unintended sharing and many concurrency bugs.
- No ARC overhead, so they are often faster and stack-allocated.
- They encourage immutability and predictable behaviour.
- Use a class only when you need reference identity, inheritance, or deinit.
7. What is the difference between struct and class?
- Struct is a value type; class is a reference type.
- Classes support inheritance and
deinit; structs do not. - Structs get a free memberwise initialiser; classes do not.
- Copying a struct duplicates data; copying a class copies only the reference.
8. What are computed properties versus stored properties?
- A stored property holds a value directly in memory.
- A computed property runs code to return (and optionally set) a value each time.
- Computed properties cannot be assigned a default value and have no backing storage.
- Use
lazystored properties to defer expensive initialisation.
9. What are property observers willSet and didSet?
willSetruns just before a stored property changes;didSetruns right after.- They are useful for reacting to state changes, e.g. reloading a view.
- They do not fire during initialisation, only on later assignments.
- Avoid heavy work inside them to keep assignments cheap.
10. What is the difference between Array, Set, and Dictionary?
Arrayis an ordered collection allowing duplicates.Setis an unordered collection of unique values with fast membership checks.Dictionaryis an unordered collection of key-value pairs.- Sets and dictionary keys require
Hashableconformance.
11. What does the mutating keyword do?
- It allows a method on a value type to modify its own properties.
- Without it, struct/enum methods cannot change
self. - It signals to callers that the method changes the instance's state.
- You cannot call a mutating method on a
letconstant instance.
12. What are enums with associated values?
- Enum cases can carry extra data, e.g.
case success(Data)/case failure(Error). - They model finite states cleanly and are pattern-matched with
switch. - Associated values differ per instance; raw values are fixed per case.
- They are great for representing results, view states, and API responses.
13. What is the difference between raw values and associated values in enums?
- Raw values are constant, same-typed values attached to each case (e.g.
Int,String). - Associated values are per-instance payloads that can differ each time.
- Raw-value enums get a failable initialiser
init?(rawValue:). - An enum can use one or the other, not both simultaneously.
14. What is type inference in Swift?
- The compiler deduces a variable's type from its initial value.
- It reduces boilerplate while staying strongly typed.
- Explicit annotations are still useful for clarity or to force a specific type.
- Inference happens at compile time, so there is no runtime cost.
15. What are tuples and when would you use them?
- A tuple groups multiple values into one compound value.
- Useful for returning several values from a function without a dedicated type.
- Elements can be named for readability, e.g.
(code: 200, message: "OK"). - For anything passed around widely, prefer a struct over a tuple.
Memory Management & ARC
16. How does ARC (Automatic Reference Counting) work?
- ARC tracks how many strong references point to each class instance.
- When the count drops to zero, the instance is deallocated automatically.
- It works at compile time by inserting retain/release calls, not a runtime garbage collector.
- ARC applies only to reference types (classes), not structs or enums.
17. What is a retain cycle and how do you break it?
- A retain cycle occurs when two objects hold strong references to each other, so neither is freed.
- It causes memory leaks because the reference count never reaches zero.
- Break it by making one reference
weakorunowned. - Common cases: delegates, closures capturing
self, parent-child object links.
18. What is the difference between weak and unowned?
weakreferences becomenilwhen the target is deallocated and must be optional.unownedassumes the target outlives the reference and is non-optional.- Use
weakwhen the other object can legitimately disappear (e.g. delegates). - Use
unownedonly when you are certain the lifetime guarantees hold, else it crashes.
19. Why do delegates use weak references?
- The delegating object usually does not own its delegate.
- A strong delegate reference would create a retain cycle with its owner.
weak var delegatelets the delegate deallocate normally.- This is the standard pattern for view-controller and view callbacks.
20. How do you avoid retain cycles in closures?
- Use a capture list
[weak self]or[unowned self]. - With
[weak self], unwrap withguard let self else { return }. - Closures are reference types, so capturing
selfstrongly keeps it alive. - Escaping closures stored as properties are the most common cycle source.
21. What is the difference between a strong, weak, and unowned capture in a closure?
- Strong (default) keeps the captured object alive as long as the closure lives.
- Weak makes the capture optional and nil-safe if the object dies.
- Unowned is non-optional and crashes if accessed after deallocation.
- Choose based on whether the captured object can outlive the closure.
22. What does deinit do?
deinitruns automatically just before a class instance is deallocated.- Use it to release resources like observers, timers, or file handles.
- Only classes have
deinit; value types do not. - Seeing (or not seeing)
deinitfire is a quick way to detect leaks.
23. What is the difference between @escaping and non-escaping closures?
- A non-escaping closure is called before the function returns and cannot outlive it.
- An
@escapingclosure may be stored and called later, e.g. completion handlers. - Escaping closures require explicit
selfcapture, surfacing retain-cycle risk. - Non-escaping is the default and allows compiler optimisations.
24. What is a memory leak and how do you detect it in iOS?
- A leak is memory that is never released because references still point to it.
- In iOS, retain cycles are the usual cause.
- Detect with Instruments' Leaks/Allocations tools and the Memory Graph Debugger.
- Confirm by checking whether
deinitis called when an object should be freed.
25. What is copy-on-write in Swift?
- Value-type collections share storage until one copy is mutated.
- On mutation, Swift makes a real copy, avoiding unnecessary duplication.
- It gives value semantics with the performance of references for reads.
- Standard types like
Array,String, andDictionaryuse it internally.
Protocols, Generics & Closures
26. What is a protocol and how is it used?
- A protocol defines a contract of methods and properties a type must implement.
- It enables polymorphism without inheritance and supports value types.
- Types adopt protocols to guarantee shared behaviour, e.g.
Equatable. - Protocols are central to delegation and protocol-oriented programming.
27. What is protocol-oriented programming?
- A Swift paradigm favouring protocols and composition over class inheritance.
- Behaviour is shared through protocol extensions with default implementations.
- It works with structs and enums, not just classes.
- It reduces fragile deep inheritance hierarchies.
28. What are protocol extensions?
- They add default method/property implementations to a protocol.
- Conforming types inherit the behaviour for free, overriding when needed.
- They let you share logic across unrelated types.
- Beware static vs dynamic dispatch differences when overriding.
29. What is the delegate pattern?
- One object delegates responsibility or callbacks to another via a protocol.
- It decouples components, e.g. a table view asking its delegate for behaviour.
- The delegate property is usually
weakto avoid cycles. - It is a one-to-one communication pattern.
30. What is the difference between delegation and closures for callbacks?
- Delegation suits multiple related callbacks grouped in a protocol.
- Closures suit single, inline callbacks like a completion handler.
- Closures keep related code together; delegates centralise it in one type.
- Closures risk retain cycles unless
selfis captured weakly.
31. What are generics and why are they useful?
- Generics let you write flexible code that works with any type.
- They keep type safety while avoiding duplicated implementations.
- Example:
func swap<T>(_ a: inout T, _ b: inout T). - The standard library's collections are built on generics.
32. What are associated types in protocols?
- An
associatedtypeis a placeholder type a conforming type specifies. - It makes protocols generic, e.g.
Elementin a container protocol. - It enables flexible, type-safe abstractions.
- Protocols with associated types cannot be used as simple existential types pre-Swift-5.7.
33. What is a closure in Swift?
- A closure is a self-contained block of functionality that can be passed around.
- It can capture and store references to variables from its surrounding scope.
- Closures are reference types.
- Functions are a special, named form of closure.
34. What is trailing closure syntax?
- When a closure is the last argument, it can be written outside the parentheses.
- It improves readability for callbacks and DSL-style APIs.
- Swift also supports multiple trailing closures with labels.
- Example:
UIView.animate(withDuration: 0.3) { ... }.
35. What is @autoclosure?
- It automatically wraps an argument expression in a closure.
- It delays evaluation until the closure is called.
- Used by
assertand??to avoid evaluating unused expressions. - Use sparingly because it hides that an argument is a closure.
Concurrency
36. What is Grand Central Dispatch (GCD)?
- GCD is Apple's low-level API for managing concurrent work via dispatch queues.
- It abstracts thread creation and pooling for you.
- You submit work to serial or concurrent queues with
async/sync. - UI work must always run on the main queue.
37. What is the difference between serial and concurrent queues?
- A serial queue runs one task at a time in order.
- A concurrent queue can run multiple tasks simultaneously.
- Serial queues help protect shared state without locks.
- The main queue is serial and dedicated to UI updates.
38. What is the difference between async and sync dispatch?
asyncsubmits work and returns immediately without waiting.syncblocks the caller until the work finishes.- Calling
syncon the current serial queue causes a deadlock. - Use
asyncfor background work and UI dispatch.
39. Why must UI updates run on the main thread?
- UIKit and SwiftUI are not thread-safe and expect main-thread access.
- Updating UI off the main thread causes glitches or crashes.
- Dispatch back with
DispatchQueue.main.asyncor@MainActor. - Network callbacks often run off-main, so always hop back for UI.
40. What is async/await in Swift?
- It is structured concurrency that writes asynchronous code in a linear style.
awaitsuspends without blocking the thread until the result is ready.- It replaces nested completion handlers and reduces callback pyramids.
- Async functions are called from an async context or a
Task.
41. What are actors in Swift concurrency?
- An actor protects its mutable state by serialising access.
- Only one task touches an actor's state at a time, preventing data races.
- Access from outside is asynchronous via
await. @MainActoris a special actor that runs work on the main thread.
42. What is the difference between GCD and async/await?
- GCD uses queues and closures; async/await uses suspension points and linear code.
- async/await offers compile-time concurrency checking and cancellation support.
- GCD is older and more manual; async/await is structured and safer.
- Both can coexist, but new code should prefer async/await.
43. What is a Task in Swift concurrency?
- A
Taskis a unit of asynchronous work that runs concurrently. - It bridges synchronous code into the async world.
- Tasks support priorities and cancellation via
Task.isCancelled. Task.detachedruns without inheriting the current context.
44. What is a race condition and how do you prevent it?
- A race condition happens when threads access shared mutable state unsafely.
- Results become unpredictable depending on timing.
- Prevent with serial queues, locks, or actors.
- Swift's actor model and Sendable checks catch many at compile time.
45. What is the difference between DispatchQueue.main.async and DispatchQueue.global().async?
main.asyncschedules work on the UI thread.global().asyncruns work on a background concurrent queue.- Do heavy work on global, then hop to main for UI updates.
- Global queues come in quality-of-service levels for prioritisation.
UIKit & View Controllers
46. What is the UIViewController lifecycle?
viewDidLoadruns once after the view loads into memory.viewWillAppear/viewDidAppearrun each time the view shows.viewWillDisappear/viewDidDisappearrun as it leaves the screen.- Use
viewDidLoadfor one-time setup andviewWillAppearfor refresh-on-show logic.
47. What is the difference between viewDidLoad and viewWillAppear?
viewDidLoadfires once when the view is created.viewWillAppearfires every time the view is about to be shown.- Put expensive one-time setup in
viewDidLoad. - Put data refresh and UI state updates in
viewWillAppear.
48. What is the difference between frame and bounds?
frameis the view's position and size in its superview's coordinate system.boundsis the view's own coordinate system, usually starting at origin (0,0).- Changing
bounds.originscrolls the content inside the view. - Rotations and transforms make
frameandboundsdiverge.
49. How does Auto Layout work?
- It positions views using constraints describing relationships, not fixed coordinates.
- The layout engine solves constraints to compute frames at runtime.
- It adapts to different screen sizes and orientations.
- Conflicting or missing constraints cause ambiguous or broken layouts.
50. What is content hugging and compression resistance?
- Content hugging resists a view growing larger than its content.
- Compression resistance resists a view shrinking smaller than its content.
- Both are priorities used to resolve layout conflicts.
- They decide which view stretches or clips when space is tight.
51. How does UITableView reuse cells?
- Cells are recycled via
dequeueReusableCell(withIdentifier:). - Offscreen cells go into a reuse pool instead of being destroyed.
- This keeps memory low and scrolling smooth for large lists.
- Always reset cell state in
prepareForReuseto avoid stale content.
52. What is the difference between UITableView and UICollectionView?
UITableViewshows a single-column vertical list.UICollectionViewsupports flexible grids and custom layouts.- Collection views use a layout object for full control of positioning.
- Use table views for simple lists, collection views for richer layouts.
53. What is a diffable data source?
- It manages table/collection data using snapshots of sections and items.
- It computes and animates differences automatically.
- It removes error-prone manual
insert/deleteindex bookkeeping. - Items must be
Hashablefor diffing to work.
54. What is the responder chain?
- It is the ordered list of objects that get a chance to handle an event.
- Events travel from the first responder up through the chain.
- It powers touch handling, menu actions, and keyboard events.
UIResponderis the base class participating in it.
55. What is the difference between pushViewController and present?
pushViewControlleradds a controller to a navigation stack with a back button.presentshows a controller modally over the current one.- Push needs a
UINavigationController; present does not. - Use push for drill-down flows, present for self-contained tasks.
56. What is the difference between Storyboards, XIBs, and programmatic UI?
- Storyboards visualise multiple screens and their transitions.
- XIBs define a single reusable view or cell visually.
- Programmatic UI builds views in code for full control and easier diffs.
- Large teams often prefer code to avoid storyboard merge conflicts.
57. What is a segue?
- A segue defines a transition between two storyboard scenes.
prepare(for:sender:)passes data to the destination.- Segues can be triggered automatically or manually with
performSegue. - Unwind segues navigate back to an earlier controller.
58. How do you pass data between view controllers?
- Forward: set properties on the destination or pass via
prepare(for:). - Backward: use delegates, closures, or notifications.
- Shared state: a view model, singleton, or dependency-injected service.
- Prefer dependency injection over global singletons for testability.
Networking, Data & Persistence
59. How do you make a network request in iOS?
- Use
URLSessionwith aURLRequest. - Handle the response on a background thread, then update UI on main.
- Modern code uses
try await URLSession.shared.data(for:). - Always handle errors, status codes, and decoding failures.
60. What is Codable and how is it used?
CodablecombinesEncodableandDecodablefor JSON conversion.- Conforming types serialise/deserialise automatically.
CodingKeysmap JSON keys to differently named properties.- Use
JSONDecoder/JSONEncoderto convert data.
61. How do you handle JSON keys that differ from property names?
- Define a
CodingKeysenum mapping properties to JSON keys. - Or set the decoder's
keyDecodingStrategyto.convertFromSnakeCase. - For complex shapes, implement custom
init(from:). - This keeps Swift naming clean while matching the API.
62. What is the difference between URLSession data, upload, and download tasks?
- Data tasks return response data in memory.
- Upload tasks send files or data to a server.
- Download tasks save responses to a file, good for large payloads.
- Download/upload tasks support background transfers.
63. What options exist for data persistence in iOS?
UserDefaultsfor small key-value settings.- Core Data or SwiftData for structured object graphs.
- SQLite/GRDB for direct relational storage.
- File system or Keychain for documents and secrets respectively.
64. What is Core Data?
- Apple's object-graph and persistence framework.
- It manages models, relationships, and change tracking.
- It is not a database itself but typically backs onto SQLite.
- It supports faulting and undo for efficient large datasets.
65. What is the difference between Core Data and SwiftData?
- SwiftData is a modern Swift-first wrapper over the same persistence stack.
- It uses
@Modelmacros instead of the visual model editor. - It integrates cleanly with SwiftUI and async/await.
- Core Data offers more mature, fine-grained control for complex needs.
66. When should you use UserDefaults?
- For small pieces of user settings and preferences.
- Examples: theme choice, onboarding-seen flag, last tab index.
- Never store large data or sensitive secrets in it.
- It persists across launches as a simple plist.
67. How do you store sensitive data securely?
- Use the Keychain, which is encrypted and access-controlled.
- Never store tokens or passwords in
UserDefaultsor plain files. - Use Secure Enclave / biometric protection for high-value secrets.
- Enable data protection so files are encrypted at rest.
68. What is the App Transport Security (ATS) requirement?
- ATS enforces secure HTTPS connections by default.
- It blocks plain HTTP unless explicitly exempted in Info.plist.
- It improves user privacy and data integrity.
- Exceptions should be rare and well justified at review time.
App Lifecycle, Architecture & Performance
69. What are the iOS app lifecycle states?
- Not running, inactive, active, background, and suspended.
- The app moves between them as the user and system interact.
- Use lifecycle callbacks to save state and release resources.
- Suspended apps stay in memory but execute no code.
70. What is the role of AppDelegate and SceneDelegate?
AppDelegatehandles app-level events like launch and notifications.SceneDelegatemanages UI scenes for multi-window support.- SwiftUI's
Appprotocol can replace much of this boilerplate. - Use
@UIApplicationDelegateAdaptorto keep a delegate in SwiftUI apps.
71. What is MVC in iOS?
- Model holds data, View shows UI, Controller mediates between them.
- It is Apple's default UIKit architecture.
- Controllers often grow huge ("Massive View Controller").
- Patterns like MVVM emerged to split responsibilities further.
72. What is MVVM and why use it?
- Model-View-ViewModel adds a view model holding presentation logic and state.
- The view binds to the view model, keeping views thin.
- It improves testability since logic lives outside the view.
- It pairs naturally with SwiftUI and Combine bindings.
73. What is dependency injection and why does it matter?
- Passing dependencies in from outside rather than creating them internally.
- It decouples components and makes them swappable.
- It enables mocking for unit tests.
- Forms include initialiser, property, and environment injection.
74. What is Combine?
- Apple's reactive framework for processing values over time.
- Publishers emit values; subscribers receive them.
- Operators transform, filter, and combine streams declaratively.
- It pairs with SwiftUI for binding asynchronous state.
75. How do you improve scrolling performance in a list?
- Reuse cells and keep cell configuration lightweight.
- Do heavy work (image decoding, formatting) off the main thread.
- Cache computed values and downsized images.
- Avoid blocking the main thread and minimise transparent overlapping layers.
76. How do you reduce an app's memory footprint?
- Release unused resources and avoid retain cycles.
- Downsample large images to display size.
- Use lazy loading and pagination for big datasets.
- Profile with Instruments to find the real hotspots.
77. What tools does Instruments provide?
- Time Profiler for CPU usage and slow code.
- Allocations and Leaks for memory issues.
- Core Animation for rendering and frame-rate problems.
- Network and Energy templates for connectivity and battery analysis.
78. What causes the main thread to be blocked and why is it bad?
- Heavy computation, synchronous I/O, or large decodes on the main thread.
- It freezes the UI and can trigger the watchdog to kill the app.
- Move such work to background queues or async tasks.
- Keep the main thread responsive at all times.
Testing, Tooling & Publishing
79. How do you write unit tests in iOS?
- Use XCTest with classes subclassing
XCTestCase. - Assert expectations with
XCTAssertfamily functions. - Use expectations for asynchronous code.
- Inject dependencies so units can be tested in isolation.
80. What is the difference between unit tests and UI tests?
- Unit tests verify isolated logic quickly without UI.
- UI tests drive the app through the interface to verify flows.
- UI tests are slower and more brittle but catch integration issues.
- A healthy suite favours many unit tests and fewer UI tests.
81. What is the difference between debug and release builds?
- Debug includes symbols and assertions, with less optimisation.
- Release is optimised and strips debug aids for performance.
- Conditional compilation can change behaviour per configuration.
- Always test performance and crashes on release builds.
82. What is a provisioning profile?
- It links your app ID, certificates, and devices for signing.
- It authorises an app to run on devices or be distributed.
- Development profiles target test devices; distribution profiles target the store.
- Mismatched profiles are a common cause of signing errors.
83. What is the difference between TestFlight and the App Store?
- TestFlight distributes beta builds to internal and external testers.
- The App Store distributes the final public release.
- TestFlight builds expire and are for feedback, not production.
- Both go through Apple processing but with different review depth.
84. What is the app review process like?
- Apple reviews submissions against its App Review Guidelines.
- Common rejections: crashes, privacy issues, broken links, guideline violations.
- You provide metadata, screenshots, and notes for reviewers.
- Rejections include reasons; you fix and resubmit.
85. How do you handle different screen sizes and devices?
- Use Auto Layout and size classes for adaptive layouts.
- Use SwiftUI's flexible stacks and geometry for responsiveness.
- Provide assets at multiple scales and use SF Symbols where possible.
- Test on the smallest and largest supported devices.
86. What is the difference between @available and runtime availability checks?
@availableannotates APIs with the OS versions they support.if #available(iOS 17, *)guards usage at runtime.- Together they let one binary support multiple OS versions safely.
- Calling newer APIs without a check crashes on older systems.
87. How do you handle push notifications?
- Request authorisation, register with APNs, and receive a device token.
- Send the token to your server, which pushes through APNs.
- Handle foreground, background, and tapped states in delegates.
- Use notification service extensions to modify payloads before display.
88. What are the best practices for app security?
- Store secrets in the Keychain and use HTTPS everywhere.
- Validate server inputs and never trust client data alone.
- Avoid hardcoding API keys; obfuscate or fetch them securely.
- Keep dependencies updated and minimise the data you collect.