History
Loading...
Loading...
September 2, 2025
@State with Result<Data, Error>? to handle async operations cleanly. This approach lets you track loading, success, and error states in a single property, making your UI logic more predictable.This pattern creates reusable error views that provide consistent user experience across your app. The `ErrorView` component encapsulates error display logic and retry functionality, while the main view focuses on business logic using clean state management with `Result` types.
struct ErrorView: View {
let error: Error
let retry: () -> Void
var body: some View {
VStack(spacing: 16) {
Image(systemName: "exclamationmark.triangle")
.font(.largeTitle)
.foregroundColor(.orange)
Text("Something went wrong")
.font(.headline)
Text(error.localizedDescription)
.font(.body)
.multilineTextAlignment(.center)
.foregroundColor(.secondary)
Button("Try Again", action: retry)
.buttonStyle(.borderedProminent)
}
.padding()
}
}
struct ContentView: View {
@State private var result: Result<[String], Error>?
var body: some View {
NavigationView {
Group {
switch result {
case .success(let items):
List(items, id: \.self) { item in
Text(item)
}
case .failure(let error):
ErrorView(error: error) {
loadData()
}
case nil:
ProgressView("Loading...")
}
}
.navigationTitle("Items")
.task { loadData() }
}
}
private func loadData() {
result = nil
// Simulate async operation
Task {
await MainActor.run {
result = .success(["Item 1", "Item 2", "Item 3"])
}
}
}
}Centralizing error handling reduces code duplication, ensures consistent UX patterns, and makes debugging easier. The `Result` type provides type safety and clear state representation, while the reusable `ErrorView` promotes maintainability and allows for easy styling updates across the entire app.