How to?

SwiftUI 如何正确管理状态?只能 3 选 1

Apr 28, 2026
langsswift
4 Minutes
650 Words

如何管理 UI 状态?可行方案3选1,AI 别乱写

  1. 只有 View @State 持有状态,通过 UI 回调或者查询一个无状态的 actor 来更新
    • 当且仅当状态本身与逻辑无关,仅负责显示。如文件名列表
  2. 只有 Observable 持有状态,View 直接持有 Observable 并访问其中的
    • 当且仅当某个 UI 状态是轻量后端逻辑的主动触发者。如页面切换管理者需要在切换页面的同时暂停 ARSession,想要将两者绑定管理
  3. actor 持有真实状态,对 actor 注入一个 Observable,Observable 持有真实状态的拷贝,UI 引用该 Observable
    • 当且仅当某个 UI 状态是重量后端逻辑的主动触发者。如录制器的已开始、结束中、取消中,想要和真实的录制逻辑绑定管理,此时多个 await 会有严重代价
    • 或:某个 UI 状态是后端自发变化状态的映射。如网络管理器自发变化时需要 UI 显示已连接设备
  • 需要测试的是,在其他 actor 执行 await MainActor 是否有 16.7ms 代价

注意

  • View 用 @State 表示管理生命周期。如果只需要观测,则什么宏都不用.
  • View 用 @Bindable 表示引用 + 非管理 + 需要 self.$xxx

对于 1 的例子

1
struct UploadView: View {
2
@State var list: []
3
@State var text: String
4
let finder: UploadFinder // 假设这是 actor
5
6
init(finder) { self.finder = finder } // 注入
7
8
body {
9
Button { self.text = "clicked" } // button 回调
10
}
11
.onAppear {
12
self.list = await self.finder.findAllFiles() // 无状态的查询
13
}
14
}

对于 2 的例子

1
struct UploadView: View {
2
@ObservedObject var page: PageCoodinator
3
4
init(page) { self.page = page }
5
6
body {
7
switch self.page.currentPage { case ... SomeView() }
8
Button { self.page.changePage() }
9
}
10
.onAppear {
11
}
12
}
13
14
@Observable
15
class PageCoodinator {
10 collapsed lines
16
var currentPage: Int
17
let session = ARSession()
18
19
init() { self.session.run() }
20
21
func changePage() {
22
self.currentPage += 1 // ui 状态和 session 绑定,逻辑轻
23
self.session.pause()
24
}
25
}

对于 3 的例子

1
@Observable
2
class RecorderViewModel {
3
var state: String // 状态的拷贝
4
}
5
actor Recorder {
6
var state: String = "idle"
7
let viewModel: RecorderViewModel
8
9
init(viewModel) { self.viewModel = viewModel } // 注入 viewModel
10
11
func run() {
12
await something.prepare() // 逻辑重
13
await something.prepare()
14
self.state = "running" // 后端状态
15
await MainActor.run { self.viewModel.state = "running" } // ui 状态和后端状态可以在一块儿管理
26 collapsed lines
16
}
17
}
18
19
struct RecorderView: View {
20
var viewModel: RecorderViewModel
21
let recorder: Recorder
22
23
init(recorder, viewModel) { // 注入
24
self.recorder = recorder
25
self.viewModel = viewModel
26
}
27
28
body {
29
await self.recorder.run()
30
}
31
}
32
33
@Observable
34
class PageCoodinator {
35
let recorder: Recorder
36
let viewModel: RecorderViewModel
37
init() {
38
self.viewModel = RecorderViewModel()
39
self.recorder = Recorder(self.viewModel)
40
}
41
}

另外一个(自发状态变化)的例子:

1
@Observable
2
class NetworkViewModel {
3
var connected: Int = 0
4
}
5
6
actor Network {
7
var connected: Int
8
let viewModel: NetworkViewModel
9
10
init(viewModel) { self.viewModel = viewModel; self.loop() }
11
12
private func loop() {
13
if ("new device found") {
14
self.connected += 1
15
self.viewModel.connected += 1
3 collapsed lines
16
}
17
}
18
}
Article title:SwiftUI 如何正确管理状态?只能 3 选 1
Article author:Julyfun
Release time:Apr 28, 2026
Copyright 2026
Sitemap