Swift interview bank

Questions interviewers actually ask, each answered at the length you would say it aloud, with the topic to reread if you were not sure.

53 questions Junior Senior
All levels Junior Mid Senior
Reveal one by one Show all answers
Report an error

Memory management

5 questions
01 What does Swift ARC automate, and what must the programmer still design? Junior common reveal ▾ hide ▴

ARC inserts and balances the retain and release operations needed for class instances. A strong reference keeps an instance alive, and after the last needed strong reference disappears, the instance can deinitialize. The programmer still designs the ownership graph. ARC does not decide whether a bidirectional property, stored callback, task, or subscription should own its target, and it does not collect an unreachable all-strong cycle. You must classify each relationship as strong, weak, or unowned and provide explicit cleanup for nonmemory resources and long-lived registrations.

Was this clear?
02 How do you choose between weak and unowned references? Mid common reveal ▾ hide ▴

Both references are nonowning, so neither keeps the target alive. Choose weak when the target may be deallocated first and absence is a valid state; ARC then sets the optional weak variable to nil. Choose unowned only when construction and encapsulation guarantee that the target outlives every access through the referrer. Ordinary unowned access traps if that guarantee is broken. The choice is semantic, not a shortcut or performance ranking. During review, look for delayed callbacks, independent caches, navigation, and cancellation that can invalidate the claimed lifetime ordering.

Was this clear?
03 How do you diagnose and repair a strong reference cycle involving a closure? Mid common reveal ▾ hide ▴

Start with storage, not closure syntax. Find who retains the closure and list every class instance that the closure captures, including a receiver hidden inside a stored method reference. A cycle exists when strong edges lead from an object to that closure and back to the object, possibly through other owners. Break one edge that does not represent ownership, often with a weak capture, and define behavior after the target disappears. Then retain an external callback copy, release the object, and test success, failure, cancellation, and delayed invocation.

Was this clear?
04 Why is adding weak self to every asynchronous closure not a safe universal rule? Senior occasional reveal ▾ hide ▴

A weak capture changes program behavior, not just memory retention. If no other owner keeps the instance alive, the closure can silently skip a save or state transition that the operation was required to finish. Conversely, binding weak self strongly at the top of a long task can retain it across every suspension point, defeating the intended early release. Decide whether work should outlive its initiator, be cancelled with it, or abandon individual steps. Then choose strong or weak capture deliberately and test the lifetime around each await and cancellation boundary.

Was this clear?
07 How do capture lists control timing and ownership in Swift closures? Mid common reveal ▾ hide ▴

Capture-list entries are evaluated when the closure is created. An entry such as [snapshot = value] preserves that evaluated value even if the outer variable is rebound later. That does not automatically mean nonownership: if the result is a class instance, snapshot strongly retains the same object. Use weak when the object may disappear first and the closure can handle nil. Use unowned only when a proven lifetime invariant guarantees the object is alive at every access. Review creation-time value semantics separately from the ownership edge that the stored entry creates.

read more Closures
Was this clear?

Language core

22 questions
05 What is a Swift closure, and what does it mean for a closure to capture a value? Junior common reveal ▾ hide ▴

A closure is a function value: it has a function type, can be stored or passed, and can be invoked later. Swift’s global functions, nested functions, and closure expressions are all closure forms. Capturing means the closure retains access to declarations from its lexical context after control leaves that context. A mutable local can live in shared capture storage, so later changes remain visible. A capture-list entry is instead initialized when the closure is created. If that entry is a class instance, it is still a strong reference unless marked weak or unowned.

read more Closures
Was this clear?
06 What is the difference between nonescaping and escaping closure parameters? Mid common reveal ▾ hide ▴

A closure parameter is nonescaping by default, so the function can’t store it or otherwise let it outlive the current call. This is a lifetime restriction, not an exactly-once guarantee: the function can invoke it zero or several times before returning. Mark the parameter @escaping when storage or later invocation requires that longer lifetime. Escaping does not itself mean asynchronous, and an escaping callback can still run before the function returns. The API must separately state call count, reentrancy, execution context, cancellation behavior, and how captured objects are owned.

read more Closures
Was this clear?
09 How do Codable, Encodable, and Decodable differ, and why might you choose only one direction? Junior common reveal ▾ hide ▴

Codable is a type alias for Encodable and Decodable together. Encodable requires encode(to:) and promises that a value can be written to an external representation; Decodable requires init(from:) and promises construction from one. Choose the narrow protocol when data flows only one way. A response-only transport model should often be Decodable so generic code cannot serialize internal fields accidentally. An outbound command may be Encodable because accepting the same shape from untrusted input was never part of its contract. This choice documents the boundary and reduces unintended capabilities.

read more Codable
Was this clear?
10 When does Swift synthesize Codable conformance, and when should you implement it manually? Mid common reveal ▾ hide ▴

Swift can synthesize each protocol requirement when the participating stored properties conform to that protocol. Without CodingKeys, property names become keys; a matching CodingKeys enum can rename fields or exclude properties that still obtain values after decoding. Computed properties are ignored. Keep synthesis when the model and external representation have the same shape. Write init(from:) or encode(to:) when you must flatten nesting, decode a discriminator, distinguish missing from null, migrate legacy fields, or apply a documented fallback. Custom code should preserve codingPath and remain strict for fields the contract requires.

read more Codable
Was this clear?
13 How do raw values and associated values differ in a Swift enum? Junior common reveal ▾ hide ▴

A raw value is one fixed literal attached to each case declaration. Every case uses the same raw-value type, values must be unique, and init?(rawValue:) can fail when external input has no matching case. An associated value is supplied whenever an enum instance is created, so different instances of one case can carry different data and different cases can carry different payload types. I use raw values for stable protocol tokens and associated values for per-event data such as an error reason, receipt, or progress measurement.

Was this clear?
14 Why should a switch over an enum you own usually avoid default? Mid common reveal ▾ hide ▴

Without default, the compiler proves that every current case is handled and points to the switch when a new case is added. A default branch throws away that maintenance signal and may send a new state through behavior written for older states. Cases that deliberately share behavior can use one comma-separated pattern without losing exhaustiveness. The main exception is an external nonfrozen enum that can evolve independently. There, @unknown default supplies a future-case path while still warning when a case known to the current SDK was omitted.

Was this clear?
15 When should you use switch, if case, guard case, or for case? Mid common reveal ▾ hide ▴

I use switch when code owns the complete dispatch decision because it preserves exhaustiveness and shows branch precedence. if case is a local Boolean-style check for one shape; guard case makes one required shape an entry condition and leaves its bindings available afterward. for case filters a sequence to matching elements and can add where for a further condition. The last three intentionally ignore alternatives, so they are poor replacements for a state machine. If skipped cases require logging, rejection, or cleanup, an ordinary loop with an exhaustive switch is clearer.

Was this clear?
16 What design checks matter for a recursive enum built from untrusted input? Senior occasional reveal ▾ hide ▴

indirect makes recursive storage possible, but it does not bound the structure or make traversal safe. At the decoding or parsing boundary, I limit depth, total nodes, and collection widths before accepting the value. I define semantics for empty composite nodes such as all([]) and any([]), then test them explicitly. The evaluator should switch exhaustively so a new grammar case requires a semantic decision. For very deep accepted structures, I consider an iterative traversal to avoid exhausting the call stack, and I keep side effects outside the recursive value model.

Was this clear?
17 Where should a Swift error be caught instead of propagated? Junior common reveal ▾ hide ▴

I catch an error at the lowest boundary that can make a truthful recovery decision. That means the layer can retry a documented transient failure, ask for corrected input, choose an explicit fallback, or translate implementation details into a stable domain error. Logging alone is not recovery, and returning a normal default after a broad catch often creates false success. If the current layer cannot change the outcome, I preserve the error and propagate it. I also test partial state before and after every throwing step, because throws does not imply rollback.

Was this clear?
18 How do typed throws and plain throws differ in Swift? Mid common reveal ▾ hide ▴

Plain throws is equivalent to throws(any Error), so the function type exposes an open failure set. A declaration such as throws(ParseError) restricts the body to that concrete error type and preserves it for callers, which enables exhaustive handling and shorter case syntax. I use typed throws when one abstraction owns a small, stable set of failures, such as an internal parser. I avoid forcing dependency failures into a closed enum merely for aesthetics, because public APIs may need evolution room. A nonthrowing function corresponds to throws(Never) and can be used where a throwing function is accepted.

Was this clear?
21 How do let and var differ, and does let make an entire object graph immutable? Junior common reveal ▾ hide ▴

let creates a binding that cannot be assigned another value after initialization, while var permits reassignment and mutation allowed by the value’s API. For a value type such as Array, a let binding prevents mutating operations on that value. For a class reference, let fixes which instance the binding refers to, but mutable properties on that instance can still change. I start with let because it exposes the few places that need mutation, then change a binding to var only when the algorithm actually reassigns or mutates that value.

Was this clear?
22 What does Swift type inference do, and when should you write an explicit type or conversion? Junior common reveal ▾ hide ▴

Type inference derives a static type from an initializer and surrounding context; it does not leave the declaration dynamically typed. I add an annotation when an empty collection needs an element type, a numeric literal should use a particular representation, or the public contract is otherwise unclear. Conversion is separate. Swift will not add Int and Double implicitly, so I choose the calculation’s units and precision before constructing the destination type. For text input, I handle the optional result of parsing rather than treating a failed conversion as zero.

Was this clear?
23 How should a beginner handle optionals at parsing and dictionary boundaries? Junior common reveal ▾ hide ▴

I first state what nil means at that boundary. Dictionary lookup may mean a field is absent, while Int(text) may mean the field exists but is malformed; those cases are not automatically equivalent. I use if let for a local two-path decision and guard let when the rest of a function requires the value. A default with ?? is correct only when absence genuinely has that default meaning. I avoid force unwraps for external data, and use a throwing or result-returning API when callers need the specific failure category for recovery or diagnostics.

Was this clear?
25 How do you choose between a structure and a class in Swift? Junior common reveal ▾ hide ▴

I start with the model’s semantics. A structure fits a value whose copies should evolve independently, such as a snapshot, coordinate, or decoded record. A class fits an entity whose stable identity and shared lifetime matter. Inheritance, deinitialization, and Objective-C interoperability can also require a class, while protocol conformance alone cannot. I do not choose from size or a stack-versus-heap slogan. I trace assignment, mutation, and ownership at call sites, start with a structure when either form works, and profile only after the semantic contract is correct.

Was this clear?
26 How does let affect a structure value versus a class reference? Junior common reveal ▾ hide ▴

For a structure, a let binding prevents mutating operations on that value, including calls to mutating methods, because those operations need write access to self. For a class, let prevents the binding from being redirected to another instance, but mutable properties on the referenced instance can still change. This means let is not deep immutability. I inspect the binding and the reachable object separately. If callers require a frozen view, I return a value snapshot or expose immutable properties instead of assuming a constant class reference protects the object graph.

Was this clear?
27 Does copying a Swift structure make its complete object graph independent? Mid common reveal ▾ hide ▴

No. Copying creates a new outer value, but each stored property follows its own semantics. A String or another ordinary value property behaves independently, while a class-typed property copies a reference to the same instance. Mutating that nested instance is then visible through both outer values. I call this a shallow-copy boundary rather than a failure of value semantics: the field’s value is the reference. For a true snapshot, I use value-typed nested state or an explicit copy operation whose ownership rules state exactly which referenced resources are duplicated or shared.

Was this clear?
29 What can a Swift extension add, and when should you use a wrapper instead? Junior common reveal ▾ hide ▴

An extension can add computed instance or type properties, methods, convenience initializers to classes, initializers to value types, subscripts, nested types, and protocol conformances. It cannot add stored properties or observers, designated class initializers, deinitializers, a superclass, or overrides of existing behavior. I use an extension when behavior derives from existing state or when separating a conformance clarifies the implementation. If the feature needs new stored state, its own invariants, distinct ownership, or a safe conformance for an external type, I introduce a wrapper rather than simulate storage globally.

read more Extensions
Was this clear?
33 What does a generic parameter preserve that Any does not? Junior common reveal ▾ hide ▴

A generic parameter preserves a compile-time relationship between every place that names it. In first([T]) -> T?, an [Int] argument produces Int?, and the implementation cannot return an unrelated String. Replacing T with Any permits heterogeneous input, but it also removes that proof, limits the body to operations available on Any, and makes callers cast results. I use Any only when runtime heterogeneity is part of the data model. When inputs and outputs should stay connected, the generic signature is the contract, not merely a reuse technique.

read more Generics
Was this clear?
38 What does a Swift optional model, and what should nil mean in an API? Junior common reveal ▾ hide ▴

Optional is an enum with .some(Wrapped) and .none; Wrapped? is its preferred shorthand, and nil denotes .none. I use it when an API has one meaningful absence state, such as a lookup miss or an omitted profile field. The contract still needs to say what nil means. I do not use nil to merge failures that callers must distinguish, such as malformed input, permission denial, and transport errors. Those need a domain error, throws, Result, or a richer enum. Empty strings, zero, false, and empty collections remain present values unless the domain explicitly normalizes them.

read more Optionals
Was this clear?
39 How do you choose among if let, guard let, optional chaining, and nil coalescing? Junior common reveal ▾ hide ▴

I use if let when both presence and absence have local behavior, and guard let when the rest of the scope requires the value and the missing path should exit early. Optional chaining fits a query or mutation where every missing link has the same outcome; it does not identify which link failed. Nil coalescing fits a fallback that is semantically equivalent to absence, and its right side is evaluated lazily. I avoid replacing malformed input with a convenient default. The choice comes from the information callers need to retain, not from which syntax produces the fewest lines.

read more Optionals
Was this clear?
42 What does Swift synthesize when you apply a property wrapper? Junior common reveal ▾ hide ▴

Swift makes the source-level property a computed interface and introduces private backing storage whose name has an underscore prefix. The backing field stores the wrapper instance, while the ordinary property delegates to its wrappedValue. If the wrapper defines projectedValue, Swift also synthesizes a dollar-prefixed projection whose type and mutability come from that member. I treat this expansion as a semantic model, not a public ABI. Consumer code should use the ordinary property and documented projection; only the enclosing type should configure underscore storage during initialization.

Was this clear?
46 How does a Swift protocol differ from class inheritance as an abstraction boundary? Junior common reveal ▾ hide ▴

A protocol describes required capabilities and can be adopted explicitly by structures, enumerations, actors, and classes. Class inheritance also supplies identity, stored state, superclass implementation, and an “is-a” hierarchy, and a class has only one direct superclass. I choose a protocol when callers need a narrow capability contract across otherwise unrelated types. I choose inheritance when subtype identity and shared superclass behavior are genuine domain requirements. Protocols do not automatically produce decoupling: a broad protocol can couple every conformer to unrelated operations just as strongly as a poor base class.

read more Protocols
Was this clear?

Concurrency

2 questions
08 How do @Sendable and @escaping differ for a closure used with concurrency? Senior occasional reveal ▾ hide ▴

@escaping permits a function value to outlive the receiving call. @Sendable says the function value can cross concurrency domains safely, which adds constraints on captured values and mutable state. The properties are orthogonal: a closure can require either one, both, or neither, and async only adds the ability to suspend. Under Swift 6 strict concurrency checking, capturing a mutable non-Sendable class or mutating shared local state can produce diagnostics. Repair the ownership or isolation design—often by moving state to an actor or passing immutable Sendable values—instead of applying @unchecked Sendable mechanically.

read more Closures
Was this clear?
44 Why does locking a property wrapper getter and setter not make compound updates atomic? Senior common reveal ▾ hide ▴

A compound expression such as count += 1 is a read followed by a write. If the wrapper locks each accessor separately, it releases the lock after the read and reacquires it for the write. Another caller can read the same old value in between, so one increment is lost. The fix is an operation that holds synchronization across the complete state transition, or actor isolation that gives the state one executor. I test the business invariant under competing calls; successful isolated reads and writes do not prove transaction-level atomicity or Sendable correctness.

Was this clear?

Data boundaries

2 questions
11 How do you evolve a Codable network model without hiding incompatible server changes? Mid common reveal ▾ hide ▴

Start from field semantics rather than making everything optional. Synthesized decoding generally ignores unknown extra object keys, so additive server fields are usually safe. A new required client property breaks old payloads with keyNotFound; use an optional or explicit default only when absence has a legitimate meaning. Preserve renamed fields with CodingKeys or migration logic. For server-extensible enums, an unknown case carrying the raw value can provide forward compatibility, but security-sensitive states may need strict rejection. Test golden payloads in both version directions and keep missing, null, wrong-type, and unknown-value cases separate.

read more Codable
Was this clear?
12 How should production code report Codable failures, and what validation remains after decoding? Senior common reveal ▾ hide ▴

Catch DecodingError at the data boundary instead of erasing it with try?. Its cases distinguish missing keys, null values, type mismatches, and corrupt data; each context carries a codingPath into nested objects and arrays. Wrap that cause in an application error while recording only approved metadata such as the model type, request identifier, category, and redacted path. Do not log complete payloads by default. Successful decoding validates representation, not business trust. Range limits, maximum sizes, URL policies, cross-field invariants, and authorization still belong in a separate validation step before constructing a trusted domain object.

read more Codable
Was this clear?

API design

6 questions
19 When should a Swift API return Result instead of throwing? Mid common reveal ▾ hide ▴

I use throws when one invocation produces a success value or transfers failure directly to its current caller. It keeps the normal path linear and composes naturally with async throws. I choose Result when the outcome itself must become data: storing attempts, placing outcomes in a collection, sending one through a callback protocol, or crossing an adapter boundary. Result does not add recovery semantics; callers still decide what to do with each failure. get() converts a stored failure back to throwing control flow, while map and mapError transform the two sides independently.

Was this clear?
20 What does rethrows guarantee, and what does it not guarantee about cleanup? Senior occasional reveal ▾ hide ▴

rethrows guarantees that a higher-order function throws only because one of its declared throwing function parameters threw. A nonthrowing argument therefore keeps the wrapper call nonthrowing. The wrapper cannot introduce an unrelated audit, cache, or configuration error without changing its declaration. defer is separate: it runs before scope exit on success or error, in last-in, first-out order, but it does not roll back external side effects. If both the body and cleanup can fail, the API must define which error has priority and how the other cause remains observable.

Was this clear?
34 Where should a generic constraint be declared? Mid common reveal ▾ hide ▴

I place a constraint on the narrowest stable capability that uses it. If a cache always stores keys in a dictionary, Key: Hashable belongs on the type because hashing supports its invariant. If only one contains method compares elements, Element: Equatable belongs on that method or a constrained extension. Conditional conformance is appropriate when the generic type adopts a protocol only for qualifying arguments. I point from every requirement to the expression that needs it. Unused constraints are not harmless documentation; they exclude valid callers and can spread through higher-level signatures.

read more Generics
Was this clear?
41 When should a Swift function return an optional instead of throwing or returning Result? Mid common reveal ▾ hide ▴

I return T? when callers need only “value” or “no result,” and absence is a normal outcome that needs no diagnostic payload. I use throws when a failure reason should alter the current caller’s control flow and propagate with context. I use Result<T, Failure> when the outcome itself must be stored, queued, combined, or delivered through a callback. try? converts errors to an optional, but it deliberately discards the reason, so it belongs only where every error has the same treatment. If there are several normal non-error states, a domain enum can be clearer than either nested optionals or overloaded nil meanings.

read more Optionals
Was this clear?
45 How should a property wrapper design its projected value? Mid occasional reveal ▾ hide ▴

projectedValue is optional API exposed as $property; it is not automatically a binding or the wrapper instance. I use it for one stable capability that complements the wrapped value, such as validation state or a narrowly scoped mutation interface. Its type, ownership, and mutability need documentation because the dollar syntax hides those choices. With composed wrappers, only the outermost projection is exposed, so the outer wrapper must deliberately forward any inner capability. I avoid returning all mutable internals, because doing so bypasses invariants and makes backing implementation order part of the consumer contract.

Was this clear?
53 When is hand-written type erasure justified, and what should you review? Senior occasional reveal ▾ hide ▴

I first check whether a native existential such as any Catalog already expresses the boundary. A hand-written wrapper is justified when it adds a stable interface, value semantics, or composition across several hidden objects that the existential does not provide. Its generic initializer should verify associated-type relationships and capture correctly typed operations; an Any dictionary plus as! is a runtime trap, not sound erasure. I also review copying, shared reference state, sendability, cancellation, and error propagation because forwarding method signatures does not define those semantics. Tests should swap conformers, copy wrappers, and exercise failures through the erased API.

Was this clear?

Collections

1 question
24 How do you choose among Array, Set, and Dictionary in Swift? Mid common reveal ▾ hide ▴

I choose from the contract, not the available methods. Array represents an ordered sequence and permits duplicates. Set represents unique Hashable elements when membership or set algebra matters, but its iteration order is not a display contract. Dictionary maps unique Hashable keys to values, and lookup returns an optional because a key may be missing. Before exposing output, I sort explicitly if order matters. I also validate external array indices before subscripting and decide whether duplicate dictionary input should be rejected, keep the first value, keep the last, or be combined.

Was this clear?

Performance and ownership

1 question
28 How does copy-on-write preserve value semantics, and what can go wrong in a custom implementation? Senior occasional reveal ▾ hide ▴

Copy-on-write lets logical values share private reference storage until one value mutates. Before every mutation path, the value checks whether its storage reference is unique and clones storage when it is not; callers therefore continue to observe independent values. A custom implementation fails if storage escapes, if any setter skips the uniqueness check, or if code treats isKnownUniquelyReferenced as synchronization. The check describes a reference at that moment and does not make concurrent mutation safe. I test all mutating APIs after copying and keep the storage class inaccessible outside the value wrapper.

Was this clear?

Protocols and dispatch

1 question
30 How does dispatch differ between a protocol requirement with a default and a member declared only in a protocol extension? Mid common reveal ▾ hide ▴

A protocol requirement has a witness in each conformance. Its extension implementation can serve as the default witness, but when a concrete type supplies the requirement, calls through an existential can reach that implementation. A member declared only in the extension has no witness slot. If the receiver’s static type is the protocol, Swift selects the extension member even when the concrete type declares a same-named method. That method is not an override. If clients need polymorphic customization, I put the member in the protocol declaration and keep only its default body in the extension.

read more Extensions
Was this clear?

Generics

1 question
31 What is the difference between a constrained extension and a conditional conformance? Mid common reveal ▾ hide ▴

A constrained extension makes its declared members available only when a where clause can be proved, such as adding contains when Element is Equatable. A conditional conformance makes the generic type itself conform to a protocol under a condition, such as Batch being Equatable only when Element is Equatable. Both are compile-time relationships, not runtime feature tests. I put each constraint on the narrowest capability that needs it, keep unconditional operations available to all type arguments, and avoid overlapping attempts to give one generic type multiple semantic conformances to the same protocol.

read more Extensions
Was this clear?

Library evolution

1 question
32 Why is a retroactive conformance risky, and what does @retroactive actually do? Senior occasional reveal ▾ hide ▴

A retroactive conformance is declared where the current module owns neither the type nor the protocol. Protocol conformances are globally unique in a process, so either upstream owner can later publish the same pair without knowing about the client declaration. Swift 6 warns about this. Writing @retroactive acknowledges responsibility and silences that warning; it does not namespace the conformance, make it file-local, or resolve a future duplicate safely. I prefer a wrapper or a protocol owned by my module, and document a migration plan when the conformance is unavoidable.

read more Extensions
Was this clear?

Protocols and generics

3 questions
35 How does an associated type differ from a generic type parameter? Mid common reveal ▾ hide ▴

Both are placeholders, but the type is selected at a different boundary. A user chooses Box when naming or constructing the generic type. A protocol conformer establishes its associated type through the members that satisfy the protocol, and generic code refers to that dependent type as C.Item. A primary associated type only adds concise constraint syntax such as some Catalog; it does not turn the protocol into an ordinary generic type. I choose the form according to who owns the decision and which same-type relationships callers must be able to express.

read more Generics
Was this clear?
36 How do generic parameters, some, and any differ in who selects the concrete type? Senior common reveal ▾ hide ▴

With <T: P>, each caller selects one concrete T and every T position preserves that identity. A parameter written as some P is shorthand for an unnamed generic parameter, so the caller still chooses a concrete type, but the implementation cannot name it elsewhere. A result written as some P is chosen by the implementation and has one hidden underlying type. An any P value can hold different conformers at runtime and preserves only the protocol interface. I use any for genuine heterogeneous storage, not as a mechanical repair for a generic constraint error.

read more Generics
Was this clear?
50 How do you choose among a generic parameter, an opaque result, and an existential in Swift? Mid common reveal ▾ hide ▴

I start with who selects the concrete type. With <T: P>, each caller chooses one T and every T position keeps that identity, so it fits algorithms with input-output relationships. A result of some P lets the implementation choose one hidden underlying type, which fits an implementation-hiding factory. An any P value can hold different conformers at runtime and exposes only the protocol boundary, which fits heterogeneous storage. I do not replace a troublesome generic with any mechanically, because that erases proofs and often introduces casts. The signature should retain every relationship consumers need and hide only details they do not.

Was this clear?

Performance and compilation

1 question
37 Can Swift code rely on every generic use being specialized? Senior occasional reveal ▾ hide ▴

No. The optimizer may specialize a generic function for concrete types, but source semantics do not promise one machine-code copy per type. Optimization level, visibility, module boundaries, resilience, and compiler version can change the result. I treat static relationships and reuse as the guaranteed benefits of generics. For performance work, I benchmark a release build on the target platform and inspect the real hot path. I do not add constraints merely to encourage specialization, because constraints first change the API contract and may exclude callers without improving the measured workload.

read more Generics
Was this clear?

Type modeling

4 questions
40 Why can a Swift dictionary lookup produce a nested optional, and when should you preserve it? Mid occasional reveal ▾ hide ▴

A Dictionary<Key, Value> subscript returns Value? because the key may be absent. If Value itself is T?, the lookup therefore has type T??. The outer layer distinguishes a missing key from a present key, while the inner layer can represent a present record with no value. I preserve both layers when those states drive different behavior, for example “no survey response” versus “response recorded but not scored.” Consecutive binding or flatMap can deliberately collapse them when the distinction is irrelevant. For a public model, a named three-case enum is often easier to read and write correctly.

read more Optionals
Was this clear?
48 How do you choose among a generic constraint, some Protocol, and any Protocol? Mid common reveal ▾ hide ▴

I start by asking who chooses the concrete type and which relationships must remain visible. A generic parameter, including parameter-position some P, lets each caller choose one type and preserves relationships involving that type. Return-position some P lets the implementation choose one fixed hidden type while retaining its identity and associated-type constraints. any P lets a variable or collection hold different conformers over time, but erases concrete identity and exposes only the protocol contract. I use any for required runtime heterogeneity, not as a shorter spelling for generics, and I constrain primary associated types when callers need that information.

read more Protocols
Was this clear?
49 What does an associated type express, and what changes when the protocol is used as any P? Senior occasional reveal ▾ hide ▴

An associated type lets a protocol name a type relationship that each conformer fixes, such as a feed’s Item or parser’s Output. Generic code can refer to that witness and relate parameters and results without choosing one concrete type globally. An any P value can hold a conformer, but erasure may hide the associated type needed for an input or cross-value relationship. Primary associated types let a signature retain selected facts, for example any Feed. If two values must share one unknown item type, I lift that type into a generic parameter rather than assuming two independent existential boxes are related.

read more Protocols
Was this clear?
51 How do associated types connect protocols to generic algorithms? Mid common reveal ▾ hide ▴

An associated type is a dependent type selected by each conformance, such as Sequence.Element or a parser’s Output. Generic code can name it as C.Element and add constraints or same-type requirements without deciding one global concrete type. That preserves relationships between protocol members and the rest of a function signature. A primary associated type only gives selected associated types concise constraint syntax such as any Catalog; it does not make the protocol an ordinary generic type. I use an associated type when one conformance owns the choice, and a method type parameter when each invocation should choose independently.

Was this clear?

Initialization

1 question
43 How is a property wrapper initialized, and why can it affect a memberwise initializer? Mid common reveal ▾ hide ▴

In a declaration such as @Rule(options) var value = initial, Swift passes initial as the wrappedValue argument and options as the remaining wrapper arguments. Without an initial value, a matching wrapper initializer or init() can initialize backing storage. An enclosing initializer can initialize through the property when init(wrappedValue:) is sufficient, or assign _value when it must configure the wrapper directly. For a structure, these capabilities also determine whether a synthesized memberwise parameter uses the original property type or the wrapper type. Public APIs should declare an explicit initializer when that signature must remain stable.

Was this clear?

Dispatch

2 questions
47 Why can a method declared only in a protocol extension behave differently through an existential? Mid common reveal ▾ hide ▴

Only members declared in the protocol are requirements with conformance witnesses. An extension can provide a default implementation for such a requirement, and a conformer’s matching implementation is then selected through the protocol boundary. A member introduced only by the extension has no witness entry; Swift resolves it from the expression’s static type. A concrete value may therefore call its same-named member while an any P value calls the extension member. If behavior is intended to vary polymorphically, I declare it in the protocol first, keep the default in the extension, and test both call paths.

read more Protocols
Was this clear?
52 Why can a protocol-extension method call a different implementation in generic code? Senior common reveal ▾ hide ▴

The first question is whether the method appears in the protocol declaration. If it is a requirement, an extension may provide a default witness, and a conformer can supply the implementation selected through the conformance. If the method exists only in the extension, generic code constrained to the protocol resolves that convenience member statically. A same-named method on the concrete type affects direct concrete calls but does not become a witness retroactively. When behavior must be customizable, I declare the requirement in the protocol and test calls through concrete, generic, and existential static types rather than only one direct call.

Was this clear?