Skip to content
intermediate Phase 14 · Advanced iOS

iOS Design Patterns

Apply singleton, observer, factory, builder, and strategy patterns in iOS context.

50m
3 problems
Topic Progress 0%

Singleton Pattern

What is a Singleton?

A Singleton ensures only one instance of a class exists. In modern Swift, use actors for thread-safe singletons:

actor DatabaseManager {
    static let shared = DatabaseManager()
    private var database: Database?
    private init() {}
    func connect() async throws {
        guard database == nil else { return }
        database = try await Database.connect()
    }
}

When to Use Singletons

  • System services (networking, database, analytics)
  • Shared resources (file manager, cache)
  • Configuration objects

Avoid singletons for business logic, view models, and test doubles.

Observer Pattern

NotificationCenter

The Observer pattern allows objects to subscribe to notifications without tight coupling:

extension Notification.Name {
    static let userDidLogin = Notification.Name("userDidLogin")
}
NotificationCenter.default.post(name: .userDidLogin, object: nil, userInfo: ["userId": user.id])

Combine Publishers

class UserModel: ObservableObject {
    @Published var name: String = ""
    @Published var isLoggedIn: Bool = false
}
struct ProfileView: View {
    @ObservedObject var user: UserModel
    var body: some View { Text(user.name) }
}

When to Use Each

  • NotificationCenter: loose coupling, cross-module
  • Combine: type-safe, composable, integrated with SwiftUI

Factory and Builder Patterns

Factory Pattern

Creates objects without specifying exact class:

protocol ViewFactory {
    func makeView() -> UIViewController
}
struct HomeViewFactory: ViewFactory {
    func makeView() -> UIViewController {
        HomeViewController(viewModel: HomeViewModel())
    }
}

Builder Pattern

Constructs complex objects step by step:

class URLRequestBuilder {
    private var request: URLRequest
    init(url: URL) { self.request = URLRequest(url: url) }
    func method(_ method: String) -> URLRequestBuilder {
        request.httpMethod = method; return self
    }
    func header(_ key: String, value: String) -> URLRequestBuilder {
        request.setValue(value, forHTTPHeaderField: key); return self
    }
    func build() -> URLRequest { request }
}

Strategy Pattern

Defines interchangeable algorithms:

protocol SortStrategy {
    func sort<T: Comparable>(_ array: inout [T])
}
struct QuickSort: SortStrategy {
    func sort<T: Comparable>(_ array: inout [T]) { array.sort() }
}

Quiz

1. When should you use the Singleton pattern?

Question 1 options

2. What problem does the Factory pattern solve?

Question 2 options

3. How does the Builder pattern differ from Factory?

Question 3 options

4. What is the Strategy pattern used for?

Question 4 options

Flashcards

Question

What is the Singleton pattern?

Answer

Provides a single shared instance of a class for global access, like NetworkManager.shared.

Question

When should you use the Factory pattern?

Answer

When you need to create objects without specifying the exact class, enabling dependency inversion.

Question

How does the Builder pattern work?

Answer

It constructs complex objects step by step using a fluent API, allowing flexible configuration.

Revision Notes

Key Takeaways

  • 1. Singletons are useful for shared resources but can create tight coupling
  • 2. Factory pattern enables dependency inversion and testability
  • 3. Builder pattern provides flexible object construction
  • 4. Strategy pattern allows swapping algorithms at runtime

Interview Tips

  • Explain when to use Singleton vs Dependency Injection
  • Discuss how Factory pattern improves testability
  • Describe the Builder pattern with a real-world example
  • Know the difference between Observer and Delegate patterns

Cheat Sheet

Design Patterns Quick Reference

  • Singleton: shared instance
  • Observer: NotificationCenter, KVO
  • Factory: creates objects via protocols
  • Builder: step-by-step construction
  • Strategy: interchangeable algorithms