Top Swift Interview Questions and Answers for 2025


Basic Swift Interview Questions


1. What is Swift?

Swift is a powerful, open-source, and type-safe programming language developed by Apple. It is optimized for performance and safety while remaining easy to read and write.

2. What are the key features of Swift?
  • Type-safe and memory-safe
  • Supports functional, object-oriented, and protocol-oriented programming
  • Optionals to handle nil values safely
  • Generics and higher-order functions
  • Automatic Reference Counting (ARC) for memory management
  • Closures and Tuples for better data handling
3. What is the difference between let and var?
Feature let (Constant) var (Variable)
Mutability Immutable Mutable
Reassignment Not Allowed Allowed
Performance More optimized Less optimized

let language = "Swift" // Cannot be changed
var version = 5.9 // Can be updated
version = 6.0

Output

language: Swift
version: 6.0
4. What are optionals in Swift? How do you unwrap an optional?
Optionals allow variables to hold a nil value, making the code safer and preventing runtime crashes.

Example of declaring an optional:

var name: String? = "John" // Can be nil

Unwrapping an optional:
  • Forced Unwrapping: name! (Unsafe, may crash if nil)
  • Optional Binding:

    if let unwrappedName = name {
        print(unwrappedName)
    }

  • Nil Coalescing Operator (??):

    print(name ?? "Default Name")

5. What is the difference between Struct and Class in Swift?
Feature Struct Class
Memory Allocation Stack Heap
Reference Type Value Type Reference Type
Inheritance Not Supported Supported
Performance Faster Slower (due to heap allocation)
Example:

struct Person {
    var name: String
}

class Animal {
    var species: String = ""
}

6. What is a tuple in Swift, and how is it used?
A tuple is a lightweight data structure that groups multiple values into a single compound value.

Example:

let person = ("John", 30)
print(person.0) // Output: John

Named tuple:

let person = (name: "John", age: 30)
print(person.name) // Output: John

7. What is the difference between guard and if statements?
Feature if Statement guard Statement
Usage Used for conditional execution Used for early exit
Scope Variables are limited to the if block Variables remain in the outer scope
Example:

func checkAge(age: Int?) {
    guard let validAge = age, validAge >= 18 else {
        print("Not eligible")
        return
    }
    print("Eligible")
}

8. What are higher-order functions in Swift? Can you name a few?
Higher-order functions take other functions as parameters or return functions.

Common higher-order functions:
  • map: Transforms elements
  • filter: Filters elements based on a condition
  • reduce: Combines elements into a single value
Example using map:

let numbers = [1, 2, 3, 4]
let squared = numbers.map { $0 * $0 }
print(squared) // Output: [1, 4, 9, 16]

9. What is type inference in Swift?
Swift automatically infers the type of a variable based on its initial value, so explicit type declaration is often unnecessary.

Example:

let name = "Swift" // Swift infers it as String
let age = 25 // Inferred as Int

10. What is a closure in Swift? Provide an example.
A closure is a self-contained block of code that can be passed around and executed later.

Example:

let greet = { (name: String) -> String in
    return "Hello, \(name)"
}
print(greet("John")) // Output: Hello, John

Advanced Swift Interview Questions


1. What is the difference between escaping and non-escaping closures in Swift?
In Swift, closures are non-escaping by default, meaning they execute immediately within the function and do not persist after the function returns. However, escaping closures are stored for later execution, often asynchronously.

Example:

func fetchData(completion: @escaping () -> Void) {
    DispatchQueue.global().async {
        // Simulating network request
        sleep(2)
        completion() // Executed later
    }
}

Here, @escaping allows completion to be stored and executed after fetchData returns.

2. What is the difference between weak, strong, and unowned references in Swift?
Reference Type Ownership Retains Object? Use Case
strong Default Yes Keeps object alive
weak No ownership No Avoids retain cycles (Optional)
unowned No ownership No Avoids retain cycles (Non-Optional)
Example:

class A {
    var name: String = "A"
}

class B {
    weak var a: A? // Avoids retain cycle
}

Here, weak var a: A? ensures A is deallocated when no other strong references exist.

3. What are property observers in Swift?
Property observers allow you to monitor and respond to changes in a property's value using willSet and didSet.

Example:

class User {
    var age: Int = 0 {
        willSet {
            print("Age will be set to \(newValue)")
        }
        didSet {
            print("Age changed from \(oldValue) to \(age)")
        }
    }
}

var user = User()
user.age = 25

Output:
Age will be set to 25
Age changed from 0 to 25
4. What is the difference between protocol, extension, and protocol extension?
Feature protocol extension protocol extension
Defines behavior Yes No No
Adds behavior No Yes Yes (for all conforming types)
Example:

protocol Greetable {
    func greet()
}

extension String {
    func reversedString() -> String {
        return String(self.reversed())
    }
}

extension Greetable {
    func greet() {
        print("Hello from protocol extension!")
    }
}

A protocol extension allows default method implementations for all conforming types.

5. What is Key-Value Observing (KVO) in Swift?
KVO allows observing property changes dynamically.

Example:

class Person: NSObject {
    @objc dynamic var name: String = "John"
}

let person = Person()
let observation = person.observe(\.name, options: [.new, .old]) { obj, change in
    print("Name changed from \(change.oldValue ?? "") to \(change.newValue ?? "")")
}
person.name = "Mike"

KVO is primarily used in Objective-C-based APIs like UIKit.

6. What is the difference between DispatchQueue.main.async and DispatchQueue.main.sync?
Method Execution Thread Blocking Use Case
async Asynchronous No UI updates, background tasks
sync Synchronous Yes (Deadlock Risk) Immediate execution, avoid in main thread
Example:

DispatchQueue.global().async {
    print("Background Task")
    DispatchQueue.main.async {
        print("UI Update")
    }
}

Using sync on DispatchQueue.main inside a main thread causes deadlock.

7. How does Codable work in Swift?
Swift’s Codable protocol combines Encodable and Decodable to serialize and deserialize JSON.

Example:

struct User: Codable {
    var name: String
    var age: Int
}

let jsonData = """ { "name": "Alice", "age": 25 } """.data(using: .utf8)!
let user = try? JSONDecoder().decode(User.self, from: jsonData)
print(user?.name ?? "") // Output: Alice

Codable simplifies working with JSON and other data formats.

8. What is a Result type in Swift?
The Result type handles success and failure cases in a structured way.

Example:

enum NetworkError: Error {
    case noInternet
}

func fetchData(completion: (Result<String, NetworkError>) -> Void) {
    let success = true
    if success {
        completion(.success("Data received"))
    } else {
        completion(.failure(.noInternet))
    }
}

fetchData { result in
    switch result {
        case .success(let data):
            print(data)
        case .failure(let error):
            print(error)
    }
}

This avoids using Optional for error handling.

9. What is lazy var in Swift?
A lazy var initializes only when accessed, improving performance.

Example:

class Example {
    lazy var expensiveComputation: String = {
        print("Computing value...")
        return "Computed"
    }()
}

let obj = Example()
print("Object created")
print(obj.expensiveComputation) // Computation happens here

Output:
Object created
Computing value...
Computed

Without lazy, the property would initialize immediately.

10. What is @autoclosure in Swift?
@autoclosure allows passing an expression as a closure without wrapping it manually.

Example:

func logMessage(_ message: @autoclosure () -> String) {
    print(message())
}

logMessage("Hello, Swift!") // No need to use `{}`

This is useful for delayed evaluation in logging or assertions.