The best examples of Swift enums with associated values: practical examples for real apps

If you’re writing Swift in 2024 and still treating enums as glorified integers, you’re leaving a lot of power on the table. The most useful way to understand them is to look at real examples of Swift enums with associated values: practical examples that mirror what you’d actually ship in a production app. Instead of abstract theory, we’ll walk through concrete patterns you can lift straight into your codebase. Swift enums with associated values let you model state, errors, and data in a way that’s both type-safe and expressive. They shine in networking, UI state, feature flags, analytics, and more. In this guide, we’ll walk through several of the best examples, from API responses and navigation flows to payment methods and authentication states. You’ll see how enums with associated values compare to optionals and structs, how they’ve evolved with modern Swift, and why they often lead to cleaner, more maintainable code than sprawling class hierarchies or loosely typed dictionaries.
Written by
Jamie
Published

Let’s skip the textbook definitions and jump straight into real examples of Swift enums with associated values: practical examples you’ll actually use.

Here’s the classic app networking scenario.

enum APIResult<Value> {
    case success(Value)
    case failure(APIError)
}

enum APIError: Error {
    case network(underlying: URLError)
    case server(statusCode: Int, message: String?)
    case decoding(underlying: Error)
    case unauthorized
    case unknown
}

func fetchUserProfile(completion: @escaping (APIResult<User>) -> Void) {
    // ... perform request
    // completion(.success(user)) or completion(.failure(.server(statusCode: 500, message: "Oops")))
}

This is one of the best examples of enums with associated values in production code:

  • APIResult.success carries the decoded value.
  • APIResult.failure carries a strongly typed error.
  • APIError.server captures HTTP status and optional message.

Instead of juggling multiple optionals or userInfo dictionaries, you get a single, expressive type that documents every path your code can take.


Navigation stacks are another place where enums shine. Modern SwiftUI apps especially benefit from this pattern.

enum AppRoute: Hashable {
    case home
    case profile(userID: String)
    case settings
    case article(id: UUID, source: ArticleSource)
}

enum ArticleSource: Hashable {
    case trending
    case bookmarked
    case shared(byUserID: String)
}

Here, the best examples of Swift enums with associated values let you encode exactly what you need to display a screen:

  • profile(userID:) carries the ID required to load that profile.
  • article(id:source:) carries both an identifier and context about where the user came from.

In SwiftUI, you can bind this directly to navigation:

@State private var route: AppRoute? = nil

NavigationStack(path: $path) {
    HomeView()
        .navigationDestination(for: AppRoute.self) { route in
            switch route {
            case .home:
                HomeView()
            case .profile(let userID):
                ProfileView(userID: userID)
            case .settings:
                SettingsView()
            case .article(let id, let source):
                ArticleDetailView(articleID: id, source: source)
            }
        }
}

This is a clean example of replacing loosely typed routing dictionaries with a single, strongly typed enum.


Modeling authentication state: examples include login, logout, and refresh

Authentication flows are notoriously messy. Enums with associated values make them much clearer.

enum AuthState {
    case loggedOut
    case loggingIn
    case loggedIn(user: User, token: AuthToken)
    case refreshingToken(oldToken: AuthToken)
    case error(message: String)
}

This is another strong example of Swift enums with associated values: practical examples of app state management.

You can drive your UI directly from this state:

func render(state: AuthState) {
    switch state {
    case .loggedOut:
        showLoginScreen()
    case .loggingIn:
        showLoadingSpinner()
    case .loggedIn(let user, _):
        showMainInterface(for: user)
    case .refreshingToken:
        showRefreshingIndicator()
    case .error(let message):
        showErrorAlert(message)
    }
}

No more “isLoggedIn” booleans scattered everywhere. One enum represents the entire lifecycle.


Payment methods and checkout: real examples from typical apps

If you’ve ever built a checkout screen, you know how messy it can get. This is where some of the best examples of Swift enums with associated values show up.

enum PaymentMethod: Hashable {
    case creditCard(number: String, expiry: Date, cvcLast4: String)
    case applePay(token: Data)
    case bankTransfer(iban: String, swiftCode: String)
    case cashOnDelivery(instructions: String?)
}

Each case represents a different payment flow, with associated values carrying the specific data needed:

func process(payment: PaymentMethod) {
    switch payment {
    case .creditCard(let number, let expiry, _):
        processCard(number: number, expiry: expiry)
    case .applePay(let token):
        processApplePay(token: token)
    case .bankTransfer(let iban, let swiftCode):
        initiateBankTransfer(iban: iban, swiftCode: swiftCode)
    case .cashOnDelivery(let instructions):
        scheduleCOD(instructions: instructions)
    }
}

Compared to a single “PaymentMethod” struct with many optionals, this enum guarantees that only the right fields exist for each method.


API request parameters: example of replacing dictionaries with enums

A lot of older Swift and Objective‑C code passes parameters as [String: Any]. That’s brittle and error‑prone. Enums with associated values give you a safer alternative.

enum SearchFilter {
    case none
    case category(id: Int)
    case priceRange(min: Decimal, max: Decimal)
    case rating(minStars: Int)
    case custom(queryItems: [URLQueryItem])
}

struct SearchRequest {
    var query: String
    var filter: SearchFilter
}

Using this pattern, your network layer can switch on the filter and build query parameters in a type‑safe way.

func buildQueryItems(for filter: SearchFilter) -> [URLQueryItem] {
    switch filter {
    case .none:
        return []
    case .category(let id):
        return [URLQueryItem(name: "category_id", value: String(id))]
    case .priceRange(let min, let max):
        return [
            URLQueryItem(name: "min_price", value: min.description),
            URLQueryItem(name: "max_price", value: max.description)
        ]
    case .rating(let minStars):
        return [URLQueryItem(name: "min_rating", value: String(minStars))]
    case .custom(let items):
        return items
    }
}

This is a practical example of how enums help you avoid stringly typed APIs.


UI state and loading flows: examples of Swift enums with associated values for screens

SwiftUI and modern UIKit architectures often model UI as state. Enums with associated values are perfect for this.

enum ScreenState<Data> {
    case idle
    case loading
    case loaded(Data)
    case empty(message: String)
    case failed(error: Error)
}

struct ArticlesViewModel {
    @Published private(set) var state: ScreenState<[Article]> = .idle

    func load() {
        state = .loading
        service.fetchArticles { result in
            DispatchQueue.main.async {
                switch result {
                case .success(let articles) where articles.isEmpty:
                    self.state = .empty(message: "No articles yet. Check back later.")
                case .success(let articles):
                    self.state = .loaded(articles)
                case .failure(let error):
                    self.state = .failed(error: error)
                }
            }
        }
    }
}

The view can then switch on state and render exactly what’s needed. This is one of the cleanest examples of Swift enums with associated values: practical examples of view models that are easy to reason about and test.


Feature flags and A/B tests: real examples for modern product teams

If you’re working on a product team in 2024, you’re probably running experiments. Enums with associated values can model feature variants better than bare strings or integers.

enum OnboardingVariant {
    case control
    case videoIntro(url: URL)
    case interactiveTutorial(steps: Int)
}

struct FeatureFlag<T> {
    let key: String
    let variant: T
}

let onboardingFlag = FeatureFlag(key: "onboarding_flow", variant: OnboardingVariant.videoIntro(url: videoURL))

When analytics or experimentation tools send down configuration, you can map raw data into enums instead of sprinkling magic strings throughout your codebase.


Analytics events: example of type-safe tracking

Tracking events is another area where enums with associated values pay off.

enum AnalyticsEvent {
    case appOpened(source: String?)
    case articleViewed(id: UUID, category: String)
    case purchaseCompleted(amount: Decimal, currency: String, success: Bool)
    case errorLogged(message: String, code: Int?, isFatal: Bool)
}

func track(_ event: AnalyticsEvent) {
    switch event {
    case .appOpened(let source):
        send("app_opened", ["source": source ?? "unknown"])
    case .articleViewed(let id, let category):
        send("article_viewed", ["id": id.uuidString, "category": category])
    case .purchaseCompleted(let amount, let currency, let success):
        send("purchase_completed", [
            "amount": amount.description,
            "currency": currency,
            "success": success.description
        ])
    case .errorLogged(let message, let code, let isFatal):
        send("error_logged", [
            "message": message,
            "code": code.map(String.init) ?? "none",
            "fatal": isFatal.description
        ])
    }
}

This is a very practical example of avoiding inconsistent event names and property keys.


Why enums with associated values beat class hierarchies in many cases

If you look across these examples of Swift enums with associated values, practical examples almost always share a theme: they replace complicated class hierarchies or loosely typed data with a single, focused type.

Compare this networking example:

class APIResponse {}
class SuccessResponse: APIResponse { let data: Any }
class ErrorResponse: APIResponse { let error: Error }

versus:

enum APIResponse<Value> {
    case success(Value)
    case error(Error)
}

The enum version is easier to pattern match, impossible to mis‑construct, and plays nicely with Swift’s switch exhaustiveness checking.

Apple’s own documentation on enumerations reinforces this pattern, showing associated values as a core language feature, not an afterthought. You can see that in the official Swift book hosted by Apple and Swift.org.


In modern Swift, especially with Swift Concurrency and SwiftUI, these patterns are becoming more common:

  • Async APIs often return enums like Result<Value, Error> or app-specific variants.
  • SwiftUI navigation, alerts, and sheets frequently bind directly to enums with associated values.
  • Domain‑driven designs in larger codebases lean heavily on enums for modeling state and workflows.

If you look at open‑source Swift projects on GitHub from the last couple of years, you’ll see many of the same patterns shown in these examples of Swift enums with associated values: practical examples focused on networking, UI state, and domain modeling.

For deeper language background, the Swift.org documentation on enumerations is worth reading: it walks through how associated values interact with pattern matching and generics in more detail.


FAQs about enums with associated values in Swift

What are some common examples of Swift enums with associated values used in apps?

Common examples include:

  • API results (success with data, failure with error)
  • Authentication state (loggedOut, loggingIn, loggedIn(user, token))
  • Screen routing and navigation (home, profile(userID:), article(id:source:))
  • Payment methods (creditCard, applePay, bankTransfer)
  • UI loading states (idle, loading, loaded(data), failed(error), empty(message))

All of these are examples of Swift enums with associated values: practical examples that directly mirror real app workflows.

Can enums with associated values conform to Codable and Hashable?

Yes. Many of the best examples in modern Swift make enums Codable, Hashable, or both. For simple cases, the compiler can synthesize these conformances automatically:

enum PaymentMethod: Codable, Hashable {
    case creditCard(number: String, expiry: Date, cvcLast4: String)
    case applePay(token: Data)
}

For more complex cases (especially when you need custom coding keys), you can implement init(from:) and encode(to:) yourself.

When should I use an enum with associated values instead of a struct?

Reach for an enum when you have a fixed set of cases and each case may carry different data. Use a struct when you have one shape of data that always exists together. If you find yourself adding several optional properties to a struct where only some are valid at a time, that’s a strong signal that an enum with associated values might be a better fit.

Can I store functions or closures as associated values?

Yes, you can. For example:

enum RetryStrategy {
    case none
    case immediate(times: Int)
    case custom(handler: (@escaping () -> Void) -> Void)
}

This is a more advanced example of Swift enums with associated values. Practical examples like this show up in networking, scheduling, or background task systems.

Do enums with associated values have performance costs?

In most app scenarios, the performance overhead is negligible. Enums are value types, and the compiler is good at optimizing them. If you’re writing performance‑critical code, the right move is to measure with Instruments rather than guessing. For most networking, UI, and domain modeling code, the clarity and safety benefits far outweigh any minor overhead.


If you take anything away from these examples of Swift enums with associated values, let it be this: whenever you catch yourself juggling state with multiple booleans, optionals, or stringly typed dictionaries, there’s a good chance an enum with associated values will give you a cleaner, more honest model of what your app is actually doing.

Explore More Swift Code Snippets

Discover more examples and insights in this category.

View All Swift Code Snippets