Skip to content
RED SAGSkills

Swift interview questions and answers

Swift questions test the language itself: optionals, value types and modern concurrency.

Below are 48 Swift questions with the correct answer and a short explanation, grouped from fresher to experienced level. Try each one before you open the answer.

What Swift interviews usually check

  • ✓Optionals and unwrapping
  • ✓Structs vs classes
  • ✓Protocols and generics
  • ✓async/await and actors
  • ✓Error handling

Swift interview questions for freshers easy

1. Swift struct assignment copies

What does this Swift code print?

struct Point { var x: Int }
var a = Point(x: 1)
var b = a
b.x = 5
print(a.x, b.x)
  1. A.5 5
  2. B.1 1
  3. C.1 5
  4. D.5 1
Show answer

Answer: C. 1 5

Structs are value types in Swift, so 'var b = a' makes an independent copy. Changing b.x does not touch a, which prints 1 5. This is why SwiftUI models data with structs: changes are local and predictable.

2. Layering views in SwiftUI

Which SwiftUI container places its child views on top of each other, for example a text label over an image?

  1. A.VStack
  2. B.HStack
  3. C.LazyVGrid
  4. D.ZStack
Show answer

Answer: D. ZStack

ZStack layers children along the depth axis, with later children drawn on top. VStack arranges children vertically and HStack horizontally. The .overlay and .background modifiers are another common way to layer one view on another.

3. Decoding JSON with extra keys

What does this Swift code print?

struct User: Codable {
  let id: Int
  let name: String
}
let json = #"{"id": 7, "name": "Sara", "age": 30}"#.data(using: .utf8)!
let user = try JSONDecoder().decode(User.self, from: json)
print(user.name)
  1. A.A DecodingError, because age is not a property of User
  2. B.Sara
  3. C.nil
  4. D.Optional("Sara")
Show answer

Answer: B. Sara

JSONDecoder ignores keys in the JSON that the type does not declare, so the extra age field is fine. name is a non-optional String, so print shows Sara without the Optional wrapper. Decoding fails only when a required key is missing or has the wrong type.

4. What await means in Swift

What happens at an await when calling an async function in Swift?

  1. A.The current thread is blocked until the result arrives, but the system starts a second main thread so the UI keeps responding
  2. B.The function may suspend there, freeing the thread for other work, and resumes when the result is ready
  3. C.The call runs in a separate process
  4. D.The call is skipped when the device is offline
Show answer

Answer: B. The function may suspend there, freeing the thread for other work, and resumes when the result is ready

await marks a possible suspension point. While the async work is in progress, the thread is free to run other code, such as drawing the UI, and the function continues later. This is why awaiting on the main actor does not freeze the app, unlike a blocking call.

5. let compared with var

What happens when you compile this code?

let price = 499
price = 549
  1. A.It compiles, and price becomes 549
  2. B.It compiles, but crashes when it runs
  3. C.Only a warning, and price stays at 499
  4. D.A compile error: a let cannot be reassigned
Show answer

Answer: D. A compile error: a let cannot be reassigned

let declares a constant that can be set only once. var declares a variable. Swift encourages let by default, which makes code easier to reason about and lets the compiler catch accidental changes.

6. Type of an optional chain

user is of type User?, and User has a non-optional property city: String. What is the type of user?.city?

  1. A.String
  2. B.String?
  3. C.String!
  4. D.Optional<String?>
Show answer

Answer: B. String?

Optional chaining returns nil if any link is nil, so the result is always optional, even if the property itself is not. The chain also flattens, so you get String?, not String??.

7. Short form of if let

Since Swift 5.7, what does "if let token { … }" mean?

  1. A.It checks whether the value of token is true
  2. B.It unwraps token into a constant with the same name
  3. C.It declares a brand new optional named token
  4. D.It compiles only when token is a Bool value
Show answer

Answer: B. It unwraps token into a constant with the same name

Swift 5.7 added shorthand unwrapping: if let token is the same as if let token = token. It also works with guard let and while let, cutting repetition.

8. Putting a struct in a Set

You try to create Set<Product> but get a compile error. What must Product conform to?

  1. A.Codable
  2. B.Identifiable
  3. C.Hashable
  4. D.CustomStringConvertible
Show answer

Answer: C. Hashable

Set and Dictionary keys need Hashable so they can be stored by hash value and compared for equality. For structs whose properties are all Hashable, adding ": Hashable" lets the compiler synthesise it.

9. Summing with reduce

What is the value of total after this code runs?

let prices = [100, 250, 50]
let total = prices.reduce(0, +)
  1. A.400
  2. B.0
  3. C.250
  4. D.[100, 250, 50]
Show answer

Answer: A. 400

reduce starts with the initial value 0 and combines each element using +. So 0 + 100 + 250 + 50 = 400. For simple sums it reads clearly and avoids a manual loop.

10. Changing a struct inside a method

A struct method that changes self.count fails to compile. What keyword is missing?

  1. A.inout
  2. B.override
  3. C.final
  4. D.mutating
Show answer

Answer: D. mutating

Struct methods cannot change properties by default because structs are value types. Marking the method mutating allows it, and it can only be called on a var instance.

11. Mapping with a key path

What does users.map(\.name) return?

  1. A.An array of each user’s name
  2. B.A dictionary keyed by name
  3. C.The first user’s name only
  4. D.A sorted copy of users
Show answer

Answer: A. An array of each user’s name

Key path expressions like \.name can be used where a function from the root type to the value is expected. users.map(\.name) is the same as users.map { $0.name }.

12. Closing a sheet from inside it

A view shown in a sheet has a "Done" button that should close it. What is the usual SwiftUI way?

  1. A.Set the parent’s window to nil directly
  2. B.Call exit(0) from the button action
  3. C.Read @Environment(\.dismiss) and call dismiss()
  4. D.Remove the view from a global array
Show answer

Answer: C. Read @Environment(\.dismiss) and call dismiss()

The dismiss environment value closes the current presentation, such as a sheet or a pushed view in a NavigationStack. The presented view does not need a binding back to the parent for this.

13. ForEach over a custom struct

ForEach(orders) { … } fails to compile for a plain struct Order. What does it need?

  1. A.Order must be Identifiable, or pass id:
  2. B.Order must be a class, not a struct
  3. C.Order must conform to Codable first
  4. D.The array must be sorted before use
Show answer

Answer: A. Order must be Identifiable, or pass id:

SwiftUI needs a stable identity for each element to track rows across updates. Conform to Identifiable with a unique id, or use ForEach(orders, id: \.orderID).

14. Fetching data with async/await

What does this line return?

let (data, response) = try await URLSession.shared.data(from: url)
  1. A.Only a String of the response body
  2. B.A Result<Data, Error> value
  3. C.A Combine publisher of Data
  4. D.A tuple of Data and URLResponse
Show answer

Answer: D. A tuple of Data and URLResponse

URLSession’s async data(from:) returns (Data, URLResponse) and throws on transport errors. You should still check the HTTP status code, because a 404 or 500 is not thrown as an error.

15. HTTP request blocked

A request to "http://api.example.com" fails with an App Transport Security error. What is the right fix?

  1. A.Use HTTPS on the server
  2. B.Retry the request three times
  3. C.Run the request on the main thread
  4. D.Lower the iOS deployment target
Show answer

Answer: A. Use HTTPS on the server

App Transport Security blocks insecure HTTP by default. The proper fix is HTTPS with modern TLS. Exceptions in Info.plist exist for special cases, but App Review may ask you to justify them.

16. Refresh token in UserDefaults

An app stores the user’s refresh token in UserDefaults. Why is this a problem, and what should it use?

  1. A.UserDefaults deletes values after 24 hours
  2. B.UserDefaults cannot store String values
  3. C.UserDefaults is a plain file; use the Keychain
  4. D.UserDefaults only works on iPad
Show answer

Answer: C. UserDefaults is a plain file; use the Keychain

UserDefaults is stored as an unencrypted property list in the app container and is included in some backups. The Keychain is built for secrets and supports access control settings.

Swift intermediate interview questions medium

17. @State vs @Binding in SwiftUI

A parent view owns an isOn Boolean. A child toggle view must read and change it. How should the child declare it?

  1. A.@State var isOn: Bool
  2. B.let isOn: Bool
  3. C.@Environment var isOn: Bool
  4. D.@Binding var isOn: Bool
Show answer

Answer: D. @Binding var isOn: Bool

The parent owns the source of truth with @State and passes $isOn to the child. The child uses @Binding, which is a two-way reference to the parent value. If the child used @State, it would create its own copy and changes would not reach the parent.

18. Owning an @Observable model

In SwiftUI on iOS 17 or later, a view creates and owns an instance of an @Observable class. How should the view store it so the instance survives when SwiftUI re-creates the view struct?

  1. A.As a plain let property
  2. B.With @Binding
  3. C.With @State
  4. D.Only through @Environment
Show answer

Answer: C. With @State

SwiftUI rebuilds view structs often, so a plain property would create a new model each time. @State gives the view persistent storage that SwiftUI keeps for the life of the view, and it works with @Observable classes. @StateObject plays this role for older ObservableObject types, while @Binding is for state owned elsewhere.

19. Constraining a generic function

What does this function require of T?

func largest<T>(_ items: [T]) -> T? where T: Comparable {
    items.max()
}
  1. A.T must be a class type only
  2. B.T must be Codable for JSON use
  3. C.T must conform to Comparable
  4. D.Nothing; T can be any type at all
Show answer

Answer: C. T must conform to Comparable

The where clause adds requirements on generic parameters. Because the body compares values with >, T must conform to Comparable. Calling it with a type that is not Comparable is a compile-time error.

20. Order of defer blocks

What does calling work() print?

func work() {
    defer { print("1") }
    defer { print("2") }
    print("3")
}
  1. A.1, 2, 3
  2. B.3, 1, 2
  3. C.1, 3, 2
  4. D.3, 2, 1
Show answer

Answer: D. 3, 2, 1

defer blocks run when the scope exits, in reverse order of declaration. The normal code prints 3 first, then the second defer prints 2, then the first prints 1. This is handy for cleanup such as closing files.

21. Result in a completion handler

Why do many callback-based APIs use completion: (Result<User, Error>) -> Void?

  1. A.It makes the callback run on the main thread
  2. B.It retries the request on failure
  3. C.It holds exactly one of success or failure, never both
  4. D.It removes the need to handle errors
Show answer

Answer: C. It holds exactly one of success or failure, never both

A pair of optionals (User?, Error?) allows confusing states like both nil. Result forces one case, and switch makes callers handle both. With async/await, throwing functions often replace it.

22. Reacting when a value changes

What does this print after cart.count = 3?

struct Cart {
    var count = 0 {
        didSet { print("Changed from \(oldValue) to \(count)") }
    }
}
var cart = Cart()
cart.count = 3
  1. A.Changed from 3 to 3
  2. B.Changed from 3 to 0
  3. C.Changed from 0 to 3
  4. D.Nothing
Show answer

Answer: C. Changed from 0 to 3

didSet runs after a stored property is assigned, and oldValue holds the previous value. willSet is the matching hook that runs before the change with newValue.

23. private or fileprivate

A property is marked private inside a struct. Where can it be accessed?

  1. A.Anywhere at all within the same module
  2. B.Only inside the method that declares it
  3. C.In any file that imports the module
  4. D.In the struct and its same-file extensions
Show answer

Answer: D. In the struct and its same-file extensions

Since Swift 4, private allows access within the declaration and its extensions in the same file. fileprivate opens access to the whole file, internal to the module, and public or open beyond it.

24. Passing a value to change it

How do you call this function so that score is updated?

func addBonus(_ value: inout Int) {
    value += 10
}
var score = 50
  1. A.addBonus(score)
  2. B.addBonus(*score)
  3. C.addBonus(inout score)
  4. D.addBonus(&score)
Show answer

Answer: D. addBonus(&score)

An inout parameter lets a function modify a caller’s variable. The call site must use & to show the value may change, and the argument must be a var. Behaviour is copy-in copy-out.

25. Why delegates are weak

A view controller owns a table helper, and the helper holds the controller as its delegate. Why is the delegate property usually weak?

  1. A.A strong reference both ways is a retain cycle that leaks
  2. B.weak makes delegate calls faster
  3. C.Delegates must be optional to compile
  4. D.weak sends delegate calls to the main thread
Show answer

Answer: A. A strong reference both ways is a retain cycle that leaks

If both objects hold strong references to each other, neither reference count reaches zero and both leak. Declaring weak var delegate (with a class-constrained protocol) breaks the cycle.

26. Cancelling a long loop

You cancel a Task that runs a long CPU loop, but the loop keeps going. Why?

  1. A.Cancellation is cooperative; the loop must check for it
  2. B.Tasks can never be cancelled once they have started
  3. C.cancel() only has an effect on the main actor
  4. D.Loops ignore cancellation unless marked @MainActor
Show answer

Answer: A. Cancellation is cooperative; the loop must check for it

cancel() only sets a flag. Code must check it, for example with try Task.checkCancellation() in the loop. Many system APIs, such as URLSession and Task.sleep, check it for you and throw CancellationError.

27. Reading a file line by line

What does this loop do?

for try await line in fileURL.lines {
    process(line)
}
  1. A.Loads the whole file into memory first
  2. B.Runs each loop iteration in parallel
  3. C.Blocks the main thread until the file is read
  4. D.Reads lines one at a time, suspending as data arrives
Show answer

Answer: D. Reads lines one at a time, suspending as data arrives

url.lines is an AsyncSequence. for try await pulls each element when it is ready, suspending between them, so large files or streams are processed without loading everything at once.

28. Opening a deep link three screens in

A push notification should open Orders → Order 42 → Invoice. Which NavigationStack setup supports this cleanly?

  1. A.Use three nested NavigationView containers
  2. B.Bind NavigationStack(path:) and append the routes
  3. C.Present each screen as a sheet, one after another
  4. D.Call pushViewController from inside SwiftUI views
Show answer

Answer: B. Bind NavigationStack(path:) and append the routes

A path binding (an array of hashable routes or NavigationPath) makes navigation state data. Setting it to [.order(42), .invoice(42)] pushes those screens, with navigationDestination(for:) mapping each route to a view.

29. Sorting inside body

A view sorts 10,000 items inside body. Scrolling is janky. Why?

  1. A.body is only called once, so sorting is not the cause
  2. B.Sorting in Swift always runs on the main thread twice
  3. C.body can be evaluated often, so heavy work repeats each time
  4. D.List cannot show sorted arrays
Show answer

Answer: C. body can be evaluated often, so heavy work repeats each time

SwiftUI may call body whenever any dependency changes. Expensive work there runs on the main thread repeatedly. Compute sorted data in the model when inputs change, and keep body a cheap description.

30. Showing a sheet for a tapped order

Tapping a row should show a sheet for that specific order. Which modifier fits best?

  1. A..sheet(isPresented: .constant(true))
  2. B..sheet(item: $selectedOrder) { order in … }
  3. C..alert(isPresented:) with the order inside
  4. D..popover on every single row
Show answer

Answer: B. .sheet(item: $selectedOrder) { order in … }

sheet(item:) presents when the optional binding is non-nil and passes the unwrapped value to the content. Setting it back to nil dismisses it. The item must be Identifiable.

31. Handling the APNs device token

After registerForRemoteNotifications(), what should the app do with the device token it receives?

  1. A.Store it once forever and never update it again
  2. B.Send it to your server each time, as it can change
  3. C.Show it to the user so they can copy it down
  4. D.Keep it only in a local variable in memory
Show answer

Answer: B. Send it to your server each time, as it can change

APNs gives a token in didRegisterForRemoteNotificationsWithDeviceToken. It can change after restore, reinstall or other events, so send the current token to your backend whenever you receive it.

32. Images reload while scrolling

A List uses AsyncImage for 500 product photos, and images reload when rows scroll back into view. Why?

  1. A.AsyncImage keeps no image cache of its own
  2. B.AsyncImage only loads images over HTTP
  3. C.List deletes rows from memory forever
  4. D.Images reload due to an iOS bug only
Show answer

Answer: A. AsyncImage keeps no image cache of its own

AsyncImage loads through URLSession and holds the image only while that view is alive. Rows leaving the screen drop it. For long lists, use an image loader with memory and disk caching.

Swift interview questions for experienced candidates hard

33. Memory leak with a closure

This view controller is never deallocated after it is dismissed. Why?

class ProfileVC: UIViewController {
  var onUpdate: (() -> Void)?
  override func viewDidLoad() {
    super.viewDidLoad()
    onUpdate = {
      self.reload()
    }
  }
  func reload() {}
}
  1. A.viewDidLoad is called twice
  2. B.Optionals always leak memory in Swift
  3. C.reload is not marked @objc
  4. D.The VC strongly holds the closure and the closure strongly captures self, creating a retain cycle; use [weak self]
Show answer

Answer: D. The VC strongly holds the closure and the closure strongly captures self, creating a retain cycle; use [weak self]

Swift uses ARC. The controller owns onUpdate, and the closure captures self strongly, so each keeps the other alive and the reference count never reaches zero. Capturing [weak self] (or unowned when lifetime is guaranteed) breaks the cycle. Xcode Memory Graph Debugger can show such cycles.

34. Task vs Task.detached

Inside a @MainActor view model method, what is the difference between starting work with Task { } and with Task.detached { }?

  1. A.Task { } inherits the current actor (here the main actor), priority and task-local values; Task.detached inherits none of them
  2. B.They are the same, but detached tasks are faster
  3. C.Task.detached always runs on the main thread
  4. D.Task { } is a child of the calling method and is cancelled when that method returns, while a detached task keeps running on its own
Show answer

Answer: A. Task { } inherits the current actor (here the main actor), priority and task-local values; Task.detached inherits none of them

A plain Task is unstructured but takes its context from where it is created, so in a @MainActor method its body runs on the main actor. Task.detached starts fresh with no actor, priority or task-locals. Neither is cancelled when the method returns; you must keep a handle and cancel it yourself.

35. unowned self in a network callback

The user closes this screen before the request finishes. What happens when the completion handler runs?

final class OrderViewController: UIViewController {
  func load() {
    api.fetchOrder { [unowned self] result in
      self.render(result)
    }
  }
}
  1. A.The closure is skipped automatically
  2. B.The app crashes, because unowned assumes self is still alive; use [weak self] with guard let self else { return }
  3. C.self is kept alive until the closure finishes, because unowned captures still hold a strong reference while a closure is pending
  4. D.It does not compile, because unowned cannot be used in closures
Show answer

Answer: B. The app crashes, because unowned assumes self is still alive; use [weak self] with guard let self else { return }

unowned does not keep the object alive and does not become nil, so accessing a deallocated object traps at runtime. It is only safe when the closure can never outlive self. For network callbacks the lifetime is unknown, so [weak self] plus a guard is the safe choice.

36. When a Swift array is copied

When is the array storage actually copied, and what does this code print?

var a = [1, 2, 3]
var b = a      // (1)
b.append(4)    // (2)
print(a.count, b.count)
  1. A.At (1), because assigning an array to a new variable always copies every element right away; it prints 3 4
  2. B.At (2), because b is mutated while it still shares storage with a; it prints 3 4
  3. C.Never; it prints 4 4
  4. D.At (2); it prints 4 4
Show answer

Answer: B. At (2), because b is mutated while it still shares storage with a; it prints 3 4

Swift arrays are value types that use copy-on-write. Assignment only shares the buffer; the real copy happens on the first mutation when the buffer is not uniquely referenced. The result still behaves like a copy, so a has 3 items and b has 4.

37. Closure capture list

What does this code print?

var count = 1
let a = { print(count) }
let b = { [count] in print(count) }
count = 2
a()
b()
  1. A.1 then 1
  2. B.2 then 2
  3. C.2 then 1
  4. D.1 then 2
Show answer

Answer: C. 2 then 1

Closures capture variables by reference by default, so a sees the updated count of 2. A capture list [count] copies the value when the closure is created, so b keeps 1.

38. imageURL is always nil

The JSON has "image_url". The struct property is imageURL: String?, and the decoder uses .convertFromSnakeCase. Why is imageURL always nil?

  1. A.The key becomes "imageUrl", which is not imageURL
  2. B.convertFromSnakeCase only works for Int fields
  3. C.Optional properties are never decoded at all
  4. D.The decoder also needs .useDefaultKeys set
Show answer

Answer: A. The key becomes "imageUrl", which is not imageURL

convertFromSnakeCase turns image_url into imageUrl, capitalising only the first letter after each underscore. imageURL does not match, and because it is optional, decoding silently gives nil. Rename to imageUrl or add CodingKeys.

39. Date decoding fails on milliseconds

The server sends "2026-10-16T10:30:00.123Z". JSONDecoder uses .iso8601 and throws a dataCorrupted error. Why?

  1. A.JSONDecoder cannot decode any Date values
  2. B.The Z suffix is invalid in ISO 8601
  3. C..iso8601 does not accept fractional seconds
  4. D.Dates must be sent as Unix timestamps
Show answer

Answer: C. .iso8601 does not accept fractional seconds

The built-in .iso8601 strategy expects no fractional seconds. Use .custom with an ISO8601DateFormatter that includes .withFractionalSeconds, or a Date.ISO8601FormatStyle that includes them, or ask the API for a consistent format.

40. Passing a class into a Task

In Swift 6 language mode, sending a mutable non-Sendable class instance from the main actor into a detached Task gives an error. Why?

  1. A.Both sides could mutate it at once, a data race
  2. B.Classes cannot be used inside any task at all
  3. C.Detached tasks only accept String values
  4. D.The class must first be marked with @objc
Show answer

Answer: A. Both sides could mutate it at once, a data race

Values crossing isolation boundaries must be Sendable, or proven safe to transfer. A mutable class shared by two concurrent contexts could race. Fixes include making it a struct, an actor, immutable and final Sendable, or not sharing it after sending.

41. Global cache in Swift 6

After switching to the Swift 6 language mode, this line reports that the variable is not concurrency-safe. What is a proper fix?

var imageCache: [URL: Data] = [:]
  1. A.Mark it lazy so it is created later
  2. B.Wrap every use in DispatchQueue.main.async
  3. C.Change it to an implicitly unwrapped optional
  4. D.Isolate it to @MainActor or move it into an actor
Show answer

Answer: D. Isolate it to @MainActor or move it into an actor

Global and static mutable variables are shared state that any thread could touch. Swift 6 rejects them unless they are isolated to a global actor, protected inside an actor, or made immutable let constants of Sendable type.

42. Using nonisolated in an actor

An actor has let id: UUID and a computed property label built only from id. Why mark label nonisolated?

  1. A.It makes label always run on the main thread
  2. B.It allows label to change mutable actor state
  3. C.It reads no mutable state, so no await is needed
  4. D.It quietly turns the actor into a class
Show answer

Answer: C. It reads no mutable state, so no await is needed

nonisolated members are not protected by the actor, so they cannot read mutable isolated state. Computing from immutable Sendable lets is safe, and making it nonisolated allows synchronous calls, for example to satisfy a protocol like Hashable.

43. Bridging a callback with a continuation

A callback API sometimes calls its completion twice. It is wrapped with withCheckedThrowingContinuation. What happens on the second resume?

  1. A.The second value replaces the first one
  2. B.A runtime trap: resume must happen exactly once
  3. C.The second call is ignored silently
  4. D.The awaiting task returns two times
Show answer

Answer: B. A runtime trap: resume must happen exactly once

Checked continuations detect misuse: resuming twice traps, and never resuming logs a leak and leaves the caller suspended forever. Guard against double callbacks, for example with a flag, before resuming.

44. Blocking inside an async function

An async function calls DispatchSemaphore.wait() to wait for another async task to signal. Under load the app hangs. Why?

  1. A.Semaphores only work when used on the main thread
  2. B.async functions cannot call any Dispatch API
  3. C.wait() always returns at once inside async code
  4. D.It blocks a pool thread that other tasks need
Show answer

Answer: D. It blocks a pool thread that other tasks need

Swift concurrency runs tasks on a small cooperative thread pool and assumes tasks never block. A blocked thread cannot run the task that would signal, which can deadlock. Use await on the other task, or async primitives like continuations.

45. How if works in a SwiftUI body

Why can you write plain if/else and several views in a row inside a SwiftUI body without return or arrays?

  1. A.Swift ignores every expression except the last one
  2. B.SwiftUI parses the body as a string at runtime
  3. C.@ViewBuilder, a result builder, combines them into one view
  4. D.Each line in the body creates a separate window
Show answer

Answer: C. @ViewBuilder, a result builder, combines them into one view

Result builders transform a block of statements into calls such as buildBlock and buildEither. @ViewBuilder uses this to combine child views and conditionals into one typed view, such as _ConditionalContent.

46. Wrong photo in a reused cell

In a UITableView, each cell starts an image download in cellForRowAt. While scrolling fast, some rows show another row’s image. What fixes it?

  1. A.Give every row its own unique reuse identifier
  2. B.Call reloadData() after every image finishes
  3. C.Download all the images on the main thread
  4. D.Reset and cancel in prepareForReuse; check the row
Show answer

Answer: D. Reset and cancel in prepareForReuse; check the row

Cells are reused, so a slow download from an earlier row can finish after the cell shows a new row. Reset the image and cancel the task in prepareForReuse, and verify the cell still represents the same item before setting the image.

47. Universal links open Safari

Universal links for example.com open Safari instead of the app. The apple-app-site-association file is reachable only through a redirect to www.example.com. What is wrong?

  1. A.Universal links only ever work for www subdomains
  2. B.The file must be renamed to aasa.txt to be found
  3. C.Universal links need the app to be open already
  4. D.The AASA file must be served over HTTPS with no redirect
Show answer

Answer: D. The AASA file must be served over HTTPS with no redirect

iOS fetches /.well-known/apple-app-site-association for each associated domain over HTTPS and does not follow redirects. Serve it directly with the right appIDs, and list each domain in the Associated Domains entitlement.

48. Importing 50,000 rows in SwiftData

An import of 50,000 records freezes the UI because it uses the main view’s ModelContext. What is the recommended approach?

  1. A.Pass the main ModelContext into a detached Task
  2. B.Insert rows on the main thread in smaller views
  3. C.Do the import in a @ModelActor with its own context
  4. D.Use UserDefaults for the import instead
Show answer

Answer: C. Do the import in a @ModelActor with its own context

ModelContext is not Sendable and the main context is tied to the main actor. A @ModelActor creates its own context from the ModelContainer on a background executor; saved changes then reach the main context.

Ready to test yourself?

Take a 15-question Swift MCQ test with a score at the end, or practise the full Swift question bank and earn points on the leaderboard.