SwiftUI 状态管理
状态的概念
在 SwiftUI 中,状态是驱动用户界面更新的关键机制。当状态发生变化时,SwiftUI 会自动更新相关的视图。
@State
@State
用于管理视图内部的简单状态:
struct CounterView: View { @State private var count = 0
var body: some View { VStack { Text("计数: \(count)")
Button("增加") { count += 1 } } }}
@Binding
@Binding
允许子视图修改父视图的状态:
struct ToggleButton: View { @Binding var isOn: Bool
var body: some View { Button(isOn ? "开启" : "关闭") { isOn.toggle() } }}
struct ParentView: View { @State private var isEnabled = false
var body: some View { ToggleButton(isOn: $isEnabled) }}
可观察对象
ObservableObject
对于更复杂的状态管理,使用 ObservableObject
:
class UserSettings: ObservableObject { @Published var username = "" @Published var isLoggedIn = false
func login() { username = "张三" isLoggedIn = true }
func logout() { username = "" isLoggedIn = false }}
@StateObject 和 @ObservedObject
struct SettingsView: View { @StateObject private var settings = UserSettings()
var body: some View { VStack { if settings.isLoggedIn { Text("欢迎, \(settings.username)!") Button("登出") { settings.logout() } } else { Button("登录") { settings.login() } } } }}
环境对象
@EnvironmentObject
使用环境对象在视图层次结构中共享数据:
class AppState: ObservableObject { @Published var theme = "light" @Published var fontSize = 14}
struct RootView: View { @StateObject private var appState = AppState()
var body: some View { ContentView() .environmentObject(appState) }}
struct ContentView: View { @EnvironmentObject var appState: AppState
var body: some View { VStack { Text("当前主题: \(appState.theme)") Button("切换主题") { appState.theme = appState.theme == "light" ? "dark" : "light" } } }}
数据流最佳实践
状态提升
当多个视图需要共享状态时,将状态提升到它们的共同父视图:
struct ParentView: View { @State private var selectedTab = 0
var body: some View { VStack { TabView(selection: $selectedTab) { FirstTabView() .tabItem { Text("第一页") } .tag(0) SecondTabView() .tabItem { Text("第二页") } .tag(1) }
// 共享状态的控制器 TabController(selectedTab: $selectedTab) } }}
依赖注入
使用依赖注入来提高代码的可测试性和可维护性:
protocol DataService { func fetchData() async throws -> [String]}
class UserDataService: DataService { func fetchData() async throws -> [String] { // 实际的网络请求 return ["数据1", "数据2"] }}
class ViewModel: ObservableObject { private let dataService: DataService @Published var items: [String] = []
init(dataService: DataService) { self.dataService = dataService }
func loadData() async { do { items = try await dataService.fetchData() } catch { print("加载失败: \(error)") } }}
练习
创建一个简单的待办事项应用,练习状态管理:
struct TodoItem: Identifiable { let id = UUID() var title: String var isCompleted: Bool}
class TodoStore: ObservableObject { @Published var items: [TodoItem] = []
func addItem(_ title: String) { items.append(TodoItem(title: title, isCompleted: false)) }
func toggleItem(_ item: TodoItem) { if let index = items.firstIndex(where: { $0.id == item.id }) { items[index].isCompleted.toggle() } }}
struct TodoListView: View { @StateObject private var store = TodoStore() @State private var newItemTitle = ""
var body: some View { VStack { List(store.items) { item in HStack { Text(item.title) Spacer() Image(systemName: item.isCompleted ? "checkmark.circle.fill" : "circle") } .onTapGesture { store.toggleItem(item) } }
HStack { TextField("新任务", text: $newItemTitle) Button("添加") { if !newItemTitle.isEmpty { store.addItem(newItemTitle) newItemTitle = "" } } } .padding() } }}
通过这个练习,你可以学习如何:
- 使用 @StateObject 管理应用状态
- 使用 @State 处理局部状态
- 实现数据的增加和更新
- 在视图中响应状态变化