ios-swiftui-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseiOS - SwiftUI Patterns
iOS - SwiftUI 模式
Modern declarative UI development for iOS, macOS, watchOS, and tvOS applications.
适用于iOS、macOS、watchOS和tvOS应用的现代声明式UI开发。
Key Concepts
核心概念
State Management Hierarchy
状态管理层级
SwiftUI provides a hierarchy of property wrappers for different state needs:
- @State: Local view state, owned by the view
- @Binding: Two-way connection to state owned elsewhere
- @StateObject: Creates and owns an ObservableObject
- @ObservedObject: References an ObservableObject owned elsewhere
- @EnvironmentObject: Dependency injection through the view hierarchy
- @Environment: Access to system-provided values
SwiftUI为不同的状态需求提供了一套属性包装器层级:
- @State:视图拥有的本地视图状态
- @Binding:与其他地方拥有的状态进行双向绑定
- @StateObject:创建并拥有一个ObservableObject
- @ObservedObject:引用其他地方拥有的ObservableObject
- @EnvironmentObject:通过视图层级进行依赖注入
- @Environment:访问系统提供的值
Observable Pattern (iOS 17+)
可观察模式(iOS 17+)
swift
@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)
}
}swift
@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)
}
}Legacy ObservableObject Pattern
传统ObservableObject模式
swift
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var isLoading: Bool = false
func fetchUser() async {
isLoading = true
defer { isLoading = false }
// fetch logic
}
}
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
// view implementation
}
}swift
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var isLoading: Bool = false
func fetchUser() async {
isLoading = true
defer { isLoading = false }
// fetch logic
}
}
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
// view implementation
}
}Best Practices
最佳实践
View Composition
视图组合
Break complex views into smaller, focused components:
swift
struct OrderSummaryView: View {
let order: Order
var body: some View {
VStack(spacing: 16) {
OrderHeaderView(order: order)
OrderItemsListView(items: order.items)
OrderTotalView(total: order.total)
}
}
}将复杂视图拆分为更小、聚焦的组件:
swift
struct OrderSummaryView: View {
let order: Order
var body: some View {
VStack(spacing: 16) {
OrderHeaderView(order: order)
OrderItemsListView(items: order.items)
OrderTotalView(total: order.total)
}
}
}Prefer Value Types
优先使用值类型
Use structs for models when possible to leverage SwiftUI's efficient diffing:
swift
struct Product: Identifiable, Equatable {
let id: UUID
var name: String
var price: Decimal
var quantity: Int
}尽可能为模型使用结构体,以利用SwiftUI高效的差异对比机制:
swift
struct Product: Identifiable, Equatable {
let id: UUID
var name: String
var price: Decimal
var quantity: Int
}Use ViewModifiers for Reusable Styling
使用ViewModifier实现可复用样式
swift
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())
}
}swift
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())
}
}Task Lifecycle for Async Work
异步任务的生命周期管理
swift
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)
}
}
}swift
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)
}
}
}Common Patterns
常见模式
Navigation with NavigationStack (iOS 16+)
使用NavigationStack进行导航(iOS 16+)
swift
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)
}
}
}
}swift
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 and Alert Presentation
弹窗与警告框的展示
swift
struct ItemView: View {
@State private var showingDetail = false
@State private var showingDeleteAlert = false
var body: some View {
Button("View Details") {
showingDetail = true
}
.sheet(isPresented: $showingDetail) {
DetailSheet()
}
.alert("Delete Item?", isPresented: $showingDeleteAlert) {
Button("Delete", role: .destructive) { deleteItem() }
Button("Cancel", role: .cancel) { }
}
}
}swift
struct ItemView: View {
@State private var showingDetail = false
@State private var showingDeleteAlert = false
var body: some View {
Button("View Details") {
showingDetail = true
}
.sheet(isPresented: $showingDetail) {
DetailSheet()
}
.alert("Delete Item?", isPresented: $showingDeleteAlert) {
Button("Delete", role: .destructive) { deleteItem() }
Button("Cancel", role: .cancel) { }
}
}
}List with SwiftData (iOS 17+)
结合SwiftData使用列表(iOS 17+)
swift
@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)
}
}
}swift
@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)
}
}
}Anti-Patterns
反模式
Avoid Large Monolithic Views
避免大型单体视图
Bad:
swift
struct BadView: View {
var body: some View {
VStack {
// 200+ lines of nested views
}
}
}Good: Extract into focused subviews.
错误示例:
swift
struct BadView: View {
var body: some View {
VStack {
// 200+ lines of nested views
}
}
}正确做法:拆分为聚焦的子视图。
Don't Use @ObservedObject for Owned State
不要为自有状态使用@ObservedObject
Bad:
swift
struct BadView: View {
@ObservedObject var viewModel = ViewModel() // Re-created on every view init!
}Good:
swift
struct GoodView: View {
@StateObject private var viewModel = ViewModel()
}错误示例:
swift
struct BadView: View {
@ObservedObject var viewModel = ViewModel() // 每次视图初始化都会重新创建!
}正确做法:
swift
struct GoodView: View {
@StateObject private var viewModel = ViewModel()
}Avoid Side Effects in View Body
避免在视图Body中产生副作用
Bad:
swift
var body: some View {
let _ = print("View rendered") // Side effect!
Text("Hello")
}Good: Use , , or for side effects.
.task.onAppear.onChange错误示例:
swift
var body: some View {
let _ = print("View rendered") // 副作用!
Text("Hello")
}正确做法:使用、或处理副作用。
.task.onAppear.onChangeDon't Force Unwrap in Views
不要在视图中强制解包
Bad:
swift
Text(user!.name) // Crash riskGood:
swift
if let user {
Text(user.name)
}错误示例:
swift
Text(user!.name) // 存在崩溃风险正确做法:
swift
if let user {
Text(user.name)
}Related Skills
相关技能
- ios-swift-concurrency: Async/await patterns for data loading
- ios-uikit-architecture: When bridging UIKit and SwiftUI
- ios-swift-concurrency:用于数据加载的Async/await模式
- ios-uikit-architecture:桥接UIKit与SwiftUI时的相关内容