The best examples of Swift enums with associated values: practical examples for real apps
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.successcarries the decoded value.APIResult.failurecarries a strongly typed error.APIError.servercaptures 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 and screen flows: another example of Swift enums with associated values
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.
2024–2025 trends: where enums with associated values are heading
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 (
successwith data,failurewith 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.
Related Topics
Practical examples of simple calculator app examples in Swift
Practical examples of Swift async/await examples for asynchronous programming
Best examples of practical examples of using closures in Swift
Practical examples of UITableView implementation in Swift for modern iOS apps
Practical examples of timer examples with Grand Central Dispatch in Swift
The best examples of error handling in Swift: 3 practical examples you’ll actually use
Explore More Swift Code Snippets
Discover more examples and insights in this category.
View All Swift Code Snippets