Swift Patterns
Modern Swift and SwiftUI patterns for iOS development.
iOS Version Selection
| Target | Best For | Stack |
|---|
| iOS 26+ | New apps, latest features | SwiftUI + SwiftData + @Observable + Foundation Models |
| iOS 17+ | Broad compatibility with modern APIs | SwiftUI + SwiftData + @Observable |
| iOS 15+ | Maximum device coverage | SwiftUI + Core Data + ObservableObject |
Reference Files
| Topic | Load | Use When |
|---|
| Project structure | references/project-structure.md | Setting up or organizing code |
| SwiftUI views | references/swiftui-patterns.md | Building UI components |
| State management | references/state-management.md | @Observable, ObservableObject, @State |
| Data persistence | references/data-persistence.md | SwiftData, Core Data, Keychain |
| Networking | references/networking.md | URLSession, API clients |
| Concurrency | references/concurrency.md | async/await, actors, tasks |
| Navigation | references/navigation.md | NavigationStack, coordinators |
| iOS 26 features | references/ios26-features.md | Liquid Glass, Foundation Models |
Quick Start Patterns
Basic SwiftUI View (iOS 17+)
import SwiftUI
struct UserProfileView: View {
@State private var viewModel = UserProfileViewModel()
var body: some View {
Group {
if viewModel.isLoading {
ProgressView()
} else if let user = viewModel.user {
VStack {
Text(user.name)
.font(.title)
Text(user.email)
.foregroundStyle(.secondary)
}
} else if let error = viewModel.error {
ContentUnavailableView(
"Error",
systemImage: "exclamationmark.triangle",
description: Text(error.localizedDescription)
)
}
}
.task {
await viewModel.loadUser()
}
}
}
Observable ViewModel (iOS 17+)
import Foundation
@Observable
class UserProfileViewModel {
var user: User?
var isLoading = false
var error: Error?
func loadUser() async {
isLoading = true
defer { isLoading = false }
do {
user = try await APIClient.shared.fetchCurrentUser()
} catch {
self.error = error
}
}
}
SwiftData Model (iOS 17+)
import SwiftData
@Model
class User {
var id: UUID
var name: String
var email: String
var createdAt: Date
init(id: UUID = UUID(), name: String, email: String) {
self.id = id
self.name = name
self.email = email
self.createdAt = Date()
}
}
Async API Call
func fetchUsers() async throws -> [User] {
let url = URL(string: "https://api.example.com/users")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw APIError.invalidResponse
}
return try JSONDecoder().decode([User].self, from: data)
}
Architecture Patterns
| Pattern | Best For | Complexity |
|---|
| MVVM | Most apps | Medium |
| TCA | Large teams, complex state | High |
| Coordinator | Complex navigation | Medium |
Essential Packages
| Package | Purpose |
|---|
| SwiftData | Persistence (iOS 17+) |
| SwiftUI | UI framework |
| Foundation | Networking, dates, etc. |
| Swift Testing | Modern testing |
| KeychainAccess | Secure storage |
Swift 6.2 Key Features
- Approachable Concurrency - Main thread by default
- @concurrent - Explicit background execution
- Typed throws - Better error handling
- @Animatable macro - Simplified animations
Code Quality Rules
- @Observable over ObservableObject - For iOS 17+
- Structured concurrency - Use async/await, not callbacks
- SwiftData over Core Data - For iOS 17+ new projects
- Swift Testing over XCTest - For new test code
- SPM over CocoaPods - For dependency management
- Value types - Prefer structs over classes when possible