Title: Swift Programming — LearnCoachAssist

Q: What is an Optional in Swift?
A: An Optional in Swift represents a variable that can hold either a value or nil. It is declared using a ? after the type, e.g., var name: String?. Optionals enforce safe handling of the absence of a value at compile time.

Q: How do you unwrap an Optional using if let?
A: You use optional binding with if let:
if let unwrapped = optionalValue {
  print(unwrapped)
}
This safely unwraps the optional and binds its value to a new constant within the block's scope.

Q: What is the difference between Optional chaining and forced unwrapping?
A: Optional chaining uses ?. and returns nil if the optional is nil, failing gracefully.
Forced unwrapping uses ! and crashes at runtime if the optional is nil.
Example: person?.name vs person!.name

Q: What is the nil-coalescing operator in Swift?
A: The nil-coalescing operator ?? provides a default value when an optional is nil.
Example: let name = optionalName ?? "Unknown"
If optionalName is nil, name is set to "Unknown".

Q: What is an implicitly unwrapped optional?
A: An implicitly unwrapped optional is declared with ! instead of ?, e.g., var name: String!. It is automatically unwrapped when accessed, but will crash if it is nil. Used when a value is guaranteed to exist after initialization.

Q: What is a Protocol in Swift?
A: A Protocol defines a blueprint of methods, properties, and other requirements for a particular task.
Example:
protocol Drawable {
  func draw()
}
Classes, structs, and enums can conform to protocols by implementing the required members.

Q: How do you add a default implementation to a protocol?
A: You use a protocol extension:
protocol Greetable {
  func greet()
}
extension Greetable {
  func greet() { print("Hello!") }
}
Conforming types inherit the default but can override it.

Q: What is protocol composition in Swift?
A: Protocol composition lets you require a type to conform to multiple protocols using the & operator.
Example: func process(item: Codable & Hashable)
The parameter must conform to both Codable and Hashable.

Q: What is a closure in Swift?
A: A closure is a self-contained block of functionality that can be passed around and used in your code. Its syntax is:
{ (parameters) -> ReturnType in
  statements
}
Closures can capture and store references to variables from their surrounding context.

Q: What is trailing closure syntax?
A: Trailing closure syntax allows you to write a closure argument after the function call's parentheses when it is the last parameter.
Example:
numbers.sorted { $0 < $1 }
instead of numbers.sorted(by: { $0 < $1 }).

Q: What does @escaping mean for a closure parameter?
A: The @escaping attribute indicates that a closure can outlive the function it is passed to, e.g., stored in a property or called asynchronously.
func fetch(completion: @escaping (Data) -> Void)
Non-escaping closures (the default) cannot be stored or called after the function returns.

Q: What are capture lists in closures?
A: A capture list defines how values are captured inside a closure, helping prevent retain cycles.
Syntax: { [weak self, unowned manager] in ... }
- [weak self] – captures self as a weak optional
- [unowned self] – captures self without increasing the reference count

Q: What is the difference between a value type and a reference type in Swift?
A: Value types (structs, enums, tuples) are copied when assigned or passed.
Reference types (classes) share a single instance via references.
Example: modifying a copy of a struct does not affect the original, but modifying a class instance through any reference changes it everywhere.

Q: When should you use a struct instead of a class?
A: Use a struct when:
- You want value semantics (independent copies)
- The data is relatively simple
- You don't need inheritance
- Thread safety via copying is desired
Apple recommends structs as the default choice in Swift.

Q: What is copy-on-write in Swift?
A: Copy-on-write (COW) is an optimization used by Swift collections like Array, Dictionary, and Set. The underlying storage is shared between copies until one copy is mutated, at which point a true copy is made. This improves performance for value types.

Q: How do you define an enum with associated values?
A: enum NetworkResult {
  case success(data: Data)
  case failure(error: Error)
}
Associated values let each case carry additional typed data, making enums powerful for modeling states with context.

Q: How do you extract associated values from an enum?
A: Use pattern matching with switch:
switch result {
case .success(let data):
  print(data)
case .failure(let error):
  print(error)
}
You can also use if case let for a single case check.

Q: What are raw values in Swift enums?
A: Raw values assign a fixed value of a specific type to each enum case:
enum Direction: String {
  case north = "N"
  case south = "S"
}
You can initialize from a raw value: Direction(rawValue: "N") returns an optional.

Q: What is the difference between associated values and raw values in enums?
A: Raw values are fixed, compile-time constants of the same type for every case.
Associated values are runtime data that can differ per instance and per case.
A single enum cannot use both raw values and associated values simultaneously.

Q: What are generics in Swift?
A: Generics let you write flexible, reusable functions and types that work with any type.
Example:
func swapValues<T>(_ a: inout T, _ b: inout T) {
  let temp = a; a = b; b = temp
}
The placeholder T is replaced with a concrete type at call time.

Q: How do you constrain a generic type in Swift?
A: Use a type constraint with a protocol or class requirement:
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int?
Here T must conform to Equatable, ensuring the == operator is available.

Q: What is a generic type in Swift?
A: A generic type is a class, struct, or enum parameterized over one or more type placeholders.
Example:
struct Stack<Element> {
  var items: [Element] = []
  mutating func push(_ item: Element) { items.append(item) }
}

Q: What is an associated type in a protocol?
A: An associated type is a placeholder type used in a protocol, defined with associatedtype:
protocol Container {
  associatedtype Item
  func add(_ item: Item)
}
Conforming types specify the concrete type for Item.

Q: What is an extension in Swift?
A: An extension adds new functionality to an existing type without modifying its source code.
extension Int {
  var isEven: Bool { self % 2 == 0 }
}
Extensions can add computed properties, methods, initializers, and protocol conformances.

Q: Can extensions add stored properties?
A: No. Extensions cannot add stored properties to a type. They can only add:
- Computed properties
- Methods
- New initializers
- Subscripts
- Nested types
- Protocol conformances

Q: How do you use extensions to organize code?
A: Extensions are commonly used to group related functionality, often by protocol conformance:
extension MyViewController: UITableViewDelegate {
  // delegate methods here
}
This keeps code organized without subclassing.

Q: How does error handling work in Swift?
A: Swift uses do-try-catch for error handling:
do {
  let data = try loadFile()
} catch FileError.notFound {
  print("Not found")
} catch {
  print(error)
}
Functions that can throw errors are marked with throws.

Q: How do you define a custom error type in Swift?
A: Create an enum conforming to the Error protocol:
enum NetworkError: Error {
  case timeout
  case notFound
  case serverError(code: Int)
}
You can then throw NetworkError.timeout inside a throws function.

Q: What is the difference between try, try?, and try!?
A: - try – used inside a do-catch block; errors must be caught
- try? – converts the result to an optional; returns nil on error
- try! – force-tries and crashes if an error is thrown
Use try? when you only care whether it succeeded.

Q: What is rethrows in Swift?
A: The rethrows keyword indicates a function only throws an error if one of its closure parameters throws.
func perform(action: () throws -> Void) rethrows
If the passed closure doesn't throw, the caller doesn't need try.

Q: What is a struct in Swift?
A: A struct is a value type that encapsulates related properties and methods.
struct Point {
  var x: Double
  var y: Double
}
Structs get an automatic memberwise initializer and are copied on assignment.

Q: What is the mutating keyword in structs?
A: The mutating keyword allows a method in a struct or enum to modify its own properties:
struct Counter {
  var count = 0
  mutating func increment() { count += 1 }
}
Without mutating, the compiler prevents property changes.

Q: What is a class in Swift?
A: A class is a reference type that supports inheritance, deinitializers, and reference counting.
class Vehicle {
  var speed: Double = 0
  func accelerate() { speed += 10 }
}
Multiple variables can reference the same class instance.

Q: What is the difference between a struct and a class in Swift?
A: Key differences:
- Struct: value type, copied on assignment, no inheritance
- Class: reference type, shared via references, supports inheritance
- Structs get a free memberwise initializer
- Classes support deinit for cleanup
- Classes use ARC for memory management

Q: What is ARC in Swift?
A: Automatic Reference Counting (ARC) automatically manages memory for class instances. It tracks how many strong references point to an object and deallocates it when the count reaches zero. weak and unowned references prevent retain cycles.

Q: What is a retain cycle and how do you prevent it?
A: A retain cycle occurs when two class instances hold strong references to each other, preventing deallocation.
Prevent it with:
- weak var delegate: SomeDelegate? – zeroed on dealloc
- unowned var parent: Parent – not zeroed, must always have a value
- [weak self] in closures

Q: What are property observers in Swift?
A: Property observers respond to changes in a property's value:
var score: Int = 0 {
  willSet { print("Will change to \(newValue)") }
  didSet { print("Changed from \(oldValue)") }
}
willSet is called before the change; didSet is called after.

Q: Can you use property observers on computed properties?
A: No. Property observers (willSet / didSet) can only be applied to stored properties. Computed properties use a getter and setter instead. However, you can add observers to inherited properties (stored or computed) via overriding.

Q: What is a lazy stored property?
A: A lazy property is not initialized until the first time it is accessed:
lazy var manager = DataManager()
This is useful for expensive initialization. Lazy properties must be declared with var and cannot be let. They are not thread-safe by default.

Q: What is a computed property in Swift?
A: A computed property does not store a value; it provides a getter (and optional setter) that calculates a value each time it is accessed:
var area: Double {
  return width * height
}
Read-only computed properties can omit the get keyword.

Q: What is a guard statement in Swift?
A: A guard statement requires a condition to be true to continue execution; otherwise it exits the current scope:
guard let name = optionalName else {
  return
}
The unwrapped value (name) remains available after the guard statement.

Q: How does guard differ from if let?
A: - guard let – unwrapped value is available in the rest of the scope; the else branch must exit (return, throw, break)
- if let – unwrapped value is only available inside the if block
guard promotes a linear, early-exit coding style.

Q: What is a defer statement in Swift?
A: A defer block is executed just before the current scope exits, regardless of how it exits:
func readFile() {
  let file = open("data.txt")
  defer { close(file) }
  // process file
}
Multiple defers execute in reverse order (LIFO).

Q: What is the difference between weak and unowned references?
A: - weak – always optional, automatically set to nil when the referenced object is deallocated
- unowned – non-optional, assumes the reference always has a value; accessing after deallocation causes a crash
Use weak when the reference may become nil; use unowned when it never will.

Q: What is type casting in Swift?
A: Type casting checks or changes the type of an instance:
- is – checks type: if item is String
- as? – conditional downcast (returns optional)
- as! – forced downcast (crashes if it fails)
Example: if let movie = item as? Movie { print(movie.title) }

Q: What are access control levels in Swift?
A: Swift has five access levels:
- open – accessible and overridable from any module
- public – accessible from any module, not overridable outside
- internal – accessible within the same module (default)
- fileprivate – accessible within the same file
- private – accessible within the enclosing declaration

Q: What is the map function on optionals?
A: The map method transforms the wrapped value of an optional if it is non-nil:
let number: Int? = 5
let result = number.map { $0 * 2 } // Optional(10)
If the optional is nil, map returns nil without executing the closure.

Q: What is the difference between map and flatMap on optionals?
A: map wraps the closure's return value in an optional, potentially creating a nested optional (Optional<Optional<T>>).
flatMap (also called compactMap on sequences) flattens the result to a single optional.
Use flatMap when your transform itself returns an optional.

Q: What is a where clause in Swift generics?
A: A where clause adds additional constraints to generic parameters:
func allEqual<T: Equatable>(_ a: T, _ b: T, _ c: T) -> Bool where T: Comparable {
  return a == b && b == c
}
It is also used in for-in, switch, and protocol extensions to refine conditions.

Q: What is a convenience initializer in Swift?
A: A convenience initializer is a secondary initializer in a class that must call a designated initializer from the same class:
class Food {
  var name: String
  init(name: String) { self.name = name }
  convenience init() { self.init(name: "Unknown") }
}