name: ios-swiftui-patterns user-invocable: false description: 在构建SwiftUI视图、使用@State/@Binding/@ObservableObject管理状态,或在iOS应用中实现声明式UI模式时使用。 allowed-tools:
- 读取
- 写入
- 编辑
- Bash
- Grep
- Glob
iOS - SwiftUI 模式
为iOS、macOS、watchOS和tvOS应用开发的现代声明式UI。
关键概念
状态管理层次
SwiftUI 提供了不同状态需求的属性包装器层次:
- @State: 局部视图状态,由视图拥有
- @Binding: 与其他地方拥有的状态双向连接
- @StateObject: 创建并拥有一个 ObservableObject
- @ObservedObject: 引用其他地方拥有的 ObservableObject
- @EnvironmentObject: 通过视图层次进行依赖注入
- @Environment: 访问系统提供的值
观察者模式 (iOS 17+)
@Observable
class UserModel {
var name: String = ""
var email: String = ""
var isLoggedIn: Bool = false
}
struct ContentView: View {
@State private var user = UserModel()
var body: some View {
UserProfileView(user: user)
}
}
传统 ObservableObject 模式
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var isLoading: Bool = false
func fetchUser() async {
isLoading = true
defer { isLoading = false }
// 获取逻辑
}
}
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
// 视图实现
}
}
最佳实践
视图组合
将复杂视图拆分为更小、专注的组件:
struct OrderSummaryView: View {
let order: Order
var body: some View {
VStack(spacing: 16) {
OrderHeaderView(order: order)
OrderItemsListView(items: order.items)
OrderTotalView(total: order.total)
}
}
}
偏好值类型
尽可能使用结构体作为模型,以利用 SwiftUI 的高效差异:
struct Product: Identifiable, Equatable {
let id: UUID
var name: String
var price: Decimal
var quantity: Int
}
使用 ViewModifiers 进行可重用样式
struct CardModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(radius: 4)
}
}
extension View {
func cardStyle() -> some View {
modifier(CardModifier())
}
}
异步工作的任务生命周期
struct UserDetailView: View {
let userId: String
@State private var user: User?
var body: some View {
Group {
if let user {
UserContent(user: user)
} else {
ProgressView()
}
}
.task {
user = await fetchUser(id: userId)
}
}
}
常见模式
使用 NavigationStack 导航 (iOS 16+)
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
ProductListView()
.navigationDestination(for: Product.self) { product in
ProductDetailView(product: product)
}
.navigationDestination(for: Category.self) { category in
CategoryView(category: category)
}
}
}
}
Sheet 和 Alert 呈现
struct ItemView: View {
@State private var showingDetail = false
@State private var showingDeleteAlert = false
var body: some View {
Button("查看详情") {
showingDetail = true
}
.sheet(isPresented: $showingDetail) {
DetailSheet()
}
.alert("删除项目?", isPresented: $showingDeleteAlert) {
Button("删除", role: .destructive) { deleteItem() }
Button("取消", role: .cancel) { }
}
}
}
使用 SwiftData 的列表 (iOS 17+)
@Model
class Task {
var title: String
var isCompleted: Bool
var createdAt: Date
init(title: String) {
self.title = title
self.isCompleted = false
self.createdAt = Date()
}
}
struct TaskListView: View {
@Query(sort: \Task.createdAt, order: .reverse)
private var tasks: [Task]
@Environment(\.modelContext) private var modelContext
var body: some View {
List(tasks) { task in
TaskRowView(task: task)
}
}
}
反模式
避免大型单一视图
坏:
struct BadView: View {
var body: some View {
VStack {
// 200+ 行嵌套视图
}
}
}
好:提取为专注的子视图。
不要将 @ObservedObject 用于拥有的状态
坏:
struct BadView: View {
@ObservedObject var viewModel = ViewModel() // 每次视图初始化时重新创建!
}
好:
struct GoodView: View {
@StateObject private var viewModel = ViewModel()
}
避免在视图主体中使用副作用
坏:
var body: some View {
let _ = print("视图渲染") // 副作用!
Text("Hello")
}
好:使用 .task, .onAppear, 或 .onChange 处理副作用。
不要在视图中强制解包
坏:
Text(user!.name) // 崩溃风险
好:
if let user {
Text(user.name)
}
相关技能
- ios-swift-concurrency: 数据加载的 async/await 模式
- ios-uikit-architecture: 桥接 UIKit 和 SwiftUI 时