LearnThatStack Ace your next interview

Swift.
Interview cheat sheet.

Quick reference for Swift - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Mobile Development 15-section reference ~7 min read

Overview

Swift is Apple's powerful and intuitive programming language for iOS, macOS, watchOS, and tvOS development. Released in 2014, Swift combines the best of modern language thinking with decades of Apple engineering expertise. It's designed to be safe, fast, and expressive, making it the primary language for Apple platform development and increasingly popular for server-side applications.

Why Swift Matters

  • Safety First: Eliminates entire classes of bugs through optionals and type safety
  • Performance: As fast as C++ for most tasks
  • Modern Syntax: Clean, expressive, and easy to read
  • ARC: Automatic memory management without garbage collection
  • Playgrounds: Interactive development and learning
  • Open Source: Cross-platform with Linux and Windows support
  • SwiftUI: Declarative UI framework integration

Basics

Variables and Constants

var mutableVariable = 10    // Can change
let immutableConstant = 20  // Cannot change

Data Types

// Basic types
let integer: Int = 42
let double: Double = 3.14
let float: Float = 3.14
let boolean: Bool = true
let string: String = "Hello"
let character: Character = "A"

// Type inference
let inferredInt = 42        // Int
let inferredString = "Hi"   // String

String Interpolation

let name = "John"
let age = 30
let message = "\(name) is \(age) years old"

Optionals

Optional Declaration

var optionalString: String? = "Hello"
var nilValue: Int? = nil

Unwrapping Optionals

// Force unwrapping (dangerous!)
let value = optionalString!

// Optional binding (safe)
if let unwrapped = optionalString {
    print(unwrapped)
}

// Guard statement
guard let unwrapped = optionalString else { return }

// Nil coalescing
let result = optionalString ?? "Default"

// Optional chaining
let length = optionalString?.count

Control Flow

If-Else

if condition {
    // code
} else if anotherCondition {
    // code
} else {
    // code
}

Switch

switch value {
case 1:
    print("One")
case 2...5:
    print("Two to Five")
case let x where x > 5:
    print("Greater than 5")
default:
    print("Other")
}

Loops

// For-in loop
for i in 1...5 { }              // 1,2,3,4,5
for i in 1..<5 { }              // 1,2,3,4
for item in array { }
for (index, value) in array.enumerated() { }

// While loop
while condition { }

// Repeat-while
repeat { } while condition

Functions & Closures

Functions

// Basic function
func greet(name: String) -> String {
    return "Hello, \(name)"
}

// Multiple parameters
func add(_ a: Int, to b: Int) -> Int {
    return a + b
}
let sum = add(5, to: 3)

// Default parameters
func greet(name: String = "World") { }

// Variadic parameters
func sum(_ numbers: Int...) -> Int {
    return numbers.reduce(0, +)
}

// inout parameters
func swap(_ a: inout Int, _ b: inout Int) {
    (a, b) = (b, a)
}

Closures

// Full syntax
let closure = { (name: String) -> String in
    return "Hello, \(name)"
}

// Trailing closure
array.map { $0 * 2 }

// Shorthand
let sorted = names.sorted(by: <)

// Capturing values
func makeIncrementer(amount: Int) -> () -> Int {
    var total = 0
    return {
        total += amount
        return total
    }
}

Classes & Structs

Struct (Value Type)

struct Point {
    var x: Double
    var y: Double
    
    // Computed property
    var magnitude: Double {
        return sqrt(x*x + y*y)
    }
    
    // Mutating method
    mutating func moveBy(x: Double, y: Double) {
        self.x += x
        self.y += y
    }
}

Class (Reference Type)

class Person {
    var name: String
    var age: Int
    
    // Designated initializer
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    // Convenience initializer
    convenience init(name: String) {
        self.init(name: name, age: 0)
    }
    
    // Deinitializer
    deinit {
        print("Person deinitialized")
    }
}

// Inheritance
class Student: Person {
    var grade: String
    
    override init(name: String, age: Int) {
        self.grade = "A"
        super.init(name: name, age: age)
    }
}

Properties

class Temperature {
    // Stored property
    var celsius: Double = 0
    
    // Computed property
    var fahrenheit: Double {
        get { return celsius * 9/5 + 32 }
        set { celsius = (newValue - 32) * 5/9 }
    }
    
    // Property observers
    var kelvin: Double = 0 {
        willSet { print("Will set to \(newValue)") }
        didSet { print("Did change from \(oldValue)") }
    }
    
    // Lazy property
    lazy var data = loadData()
    
    // Static property
    static let boilingPoint = 100.0
}

Protocols & Extensions

Protocols

protocol Vehicle {
    var wheels: Int { get }
    func drive()
}

// Protocol with default implementation
protocol Greetable {
    var name: String { get }
}

extension Greetable {
    func greet() {
        print("Hello, \(name)")
    }
}

// Conforming to protocol
struct Car: Vehicle {
    let wheels = 4
    func drive() { print("Driving") }
}

Extensions

// Extend existing types
extension Int {
    var squared: Int { return self * self }
    
    func times(closure: () -> Void) {
        for _ in 0..<self { closure() }
    }
}

// Usage
let squared = 5.squared  // 25
3.times { print("Hi") }

Memory Management

ARC (Automatic Reference Counting)

// Strong reference (default)
var strongRef = Person()

// Weak reference (optional, no ownership)
weak var weakRef: Person?

// Unowned reference (non-optional, no ownership)
unowned let unownedRef: Person

// Closure capture lists
someFunction { [weak self] in
    self?.doSomething()
}

// Avoiding retain cycles
class Node {
    var value: Int
    weak var parent: Node?  // Weak to avoid cycle
    var children: [Node] = []
}

Error Handling

Throwing Functions

enum ValidationError: Error {
    case tooShort, tooLong
}

func validate(_ password: String) throws -> Bool {
    guard password.count >= 6 else {
        throw ValidationError.tooShort
    }
    guard password.count <= 20 else {
        throw ValidationError.tooLong
    }
    return true
}

Handling Errors

// Do-catch
do {
    try validate(password)
} catch ValidationError.tooShort {
    print("Password too short")
} catch {
    print("Unknown error: \(error)")
}

// Try? (returns optional)
let result = try? validate(password)

// Try! (force, crashes on error)
let result = try! validate(password)

Generics

Generic Functions

func swap<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

Generic Types

struct Stack<Element> {
    private var items: [Element] = []
    
    mutating func push(_ item: Element) {
        items.append(item)
    }
    
    mutating func pop() -> Element? {
        return items.popLast()
    }
}

Generic Constraints

func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
    for (index, item) in array.enumerated() {
        if item == value { return index }
    }
    return nil
}

Concurrency

Grand Central Dispatch (GCD)

// Main queue (UI updates)
DispatchQueue.main.async {
    // Update UI
}

// Background queue
DispatchQueue.global(qos: .background).async {
    // Heavy work
}

// Custom queue
let queue = DispatchQueue(label: "com.app.queue")
queue.async { }

Modern Concurrency (async/await)

// Async function
func fetchData() async throws -> Data {
    let url = URL(string: "https://api.example.com")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}

// Using async function
Task {
    do {
        let data = try await fetchData()
    } catch {
        print("Error: \(error)")
    }
}

// Async let (concurrent)
async let photo1 = downloadPhoto(id: 1)
async let photo2 = downloadPhoto(id: 2)
let photos = await [photo1, photo2]

Collections

Array

var array = [1, 2, 3]
array.append(4)
array.insert(0, at: 0)
array.remove(at: 1)
array.contains(3)  // true

// Common operations
let mapped = array.map { $0 * 2 }
let filtered = array.filter { $0 > 2 }
let sum = array.reduce(0, +)
let sorted = array.sorted()

Dictionary

var dict = ["key": "value"]
dict["newKey"] = "newValue"
dict.removeValue(forKey: "key")

// Safe access
if let value = dict["key"] { }

// Iterating
for (key, value) in dict { }

Set

var set: Set = [1, 2, 3]
set.insert(4)
set.remove(2)
set.contains(3)  // true

// Set operations
let union = set1.union(set2)
let intersection = set1.intersection(set2)
let difference = set1.subtracting(set2)

Common Patterns

Singleton

class NetworkManager {
    static let shared = NetworkManager()
    private init() { }
}

Delegate Pattern

protocol TableViewDelegate: AnyObject {
    func didSelectRow(at index: Int)
}

class TableView {
    weak var delegate: TableViewDelegate?
    
    func selectRow(at index: Int) {
        delegate?.didSelectRow(at: index)
    }
}

Observer Pattern

class Observable<T> {
    var value: T {
        didSet { listener?(value) }
    }
    
    private var listener: ((T) -> Void)?
    
    init(_ value: T) {
        self.value = value
    }
    
    func bind(_ listener: @escaping (T) -> Void) {
        self.listener = listener
        listener(value)
    }
}

Factory Pattern

protocol Animal {
    func makeSound()
}

class AnimalFactory {
    static func create(type: String) -> Animal? {
        switch type {
        case "dog": return Dog()
        case "cat": return Cat()
        default: return nil
        }
    }
}

Interview Tips

Common Questions

  1. Value vs Reference Types: Structs are value types (copied), Classes are reference types (shared)
  2. ARC: Swift uses Automatic Reference Counting for memory management
  3. Optionals: Use to handle absence of value safely
  4. Protocol-Oriented Programming: Prefer protocols over inheritance
  5. Access Control: private, fileprivate, internal (default), public, open

Best Practices

  • Use let over var when possible
  • Prefer structs over classes unless you need reference semantics
  • Use guard for early exits
  • Avoid force unwrapping
  • Use meaningful variable names
  • Follow Swift naming conventions (camelCase)
  • Use extensions to organize code
  • Implement proper error handling

Performance Tips

  • Use lazy for expensive computations
  • Prefer isEmpty over count == 0
  • Use ContiguousArray for performance-critical code
  • Avoid unnecessary type conversions
  • Use value types to reduce heap allocations

SwiftUI Basics (if asked)

struct ContentView: View {
    @State private var count = 0
    
    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("Increment") {
                count += 1
            }
        }
    }
}
Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime