logo
SwiftUI 入门

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()
}
}
}

通过这个练习,你可以学习如何:

  1. 使用 @StateObject 管理应用状态
  2. 使用 @State 处理局部状态
  3. 实现数据的增加和更新
  4. 在视图中响应状态变化