0Pricing
Swift Academy · 课时

将视图模型绑定到视图

使用 SwiftUI 和 Combine 连接视图模型。

将视图模型绑定到视图 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

将视图模型连接到视图

只有当视图响应视图模型的变化时,视图模型才有用。在 SwiftUI 中,这种响应式能力由基于 Combine 的属性包装器 @Published、@StateObject 和 @ObservedObject 提供。

它们共同形成自动绑定:视图模型发生变化时,视图会重新渲染。

ObservableObject

要让 SwiftUI 观察视图模型,视图模型必须遵循 ObservableObject。该协议为它提供了一个 objectWillChange 发布者,该发布者会在任何变化发生前触发。

final class CounterViewModel: ObservableObject {
    @Published var count: Int = 0

    func increment() {
        count += 1
    }
}

@Published 属性

使用 @Published 标记属性后,每当该属性被设置新值时,系统都会自动发出变化通知。

每个 @Published 属性都会向对象的 objectWillChange 发布者提供变化,因此视图能够准确知道何时刷新。

final class SearchViewModel: ObservableObject {
    @Published var query: String = ""
    @Published var results: [String] = []
}

@StateObject

@StateObject 告诉视图创建并拥有一个视图模型。SwiftUI 会实例化它一次,并在该视图重新渲染期间保持它存活。

在首次创建视图模型的地方使用 @StateObject。

struct CounterView: View {
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        Button("Count: \(viewModel.count)") {
            viewModel.increment()
        }
    }
}

@ObservedObject

@ObservedObject用于已经在其他地方创建并传入的视图模型。视图会观察它,但不负责管理它的生命周期。

对于从父级接收视图模型的子级视图,请使用它。

struct BadgeView: View {
    @ObservedObject var viewModel: CounterViewModel

    var body: some View {
        Text("Total: \(viewModel.count)")
    }
}

StateObject 与 ObservedObject

关键区别在于所有权:

  • @StateObject — 由视图拥有;在重新渲染后仍然保留
  • @ObservedObject — 从外部传入;不由视图拥有

应该使用 @StateObject 却使用了 @ObservedObject,可能会导致对象在每次父级更新时重新创建并丢失状态。

向下传递视图模型

在父级中使用 @StateObject 创建一次视图模型,然后将它传递给使用 @ObservedObject 标记的子级。

struct ParentView: View {
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        VStack {
            BadgeView(viewModel: viewModel)
            Button("Add") { viewModel.increment() }
        }
    }
}

双向绑定

对于文本字段等输入控件,您需要双向绑定。SwiftUI 使用包装器上的 $ 前缀,根据 @Published 属性生成绑定。

struct SearchView: View {
    @StateObject private var viewModel = SearchViewModel()

    var body: some View {
        TextField("Search", text: $viewModel.query)
    }
}

驱动用户界面状态

视图应该从已发布的属性中派生出所有要显示的内容。加载指示器、错误横幅和内容都由视图模型状态驱动。

final class FeedViewModel: ObservableObject {
    enum State { case loading, loaded([String]), error(String) }
    @Published var state: State = .loading
}

响应状态

视图根据视图模型状态进行切换,以渲染正确的用户界面。这里没有命令式的显示或隐藏代码,只有声明式映射。

struct FeedView: View {
    @StateObject var viewModel = FeedViewModel()
    var body: some View {
        switch viewModel.state {
        case .loading: ProgressView()
        case .loaded(let items): List(items, id: \.self) { Text($0) }
        case .error(let message): Text(message)
        }
    }
}

在主线程上保持更新

SwiftUI 要求在主线程上发布变化。当视图模型在异步工作完成后更新状态时,请使用 @MainActor 标注它,以确保这一点。

@MainActor
final class ProfileViewModel: ObservableObject {
    @Published var name: String = ""

    func load() async {
        name = await fetchName()
    }
}

快速检查

测试您对绑定的理解。

回顾

您已经使用 SwiftUI 绑定将视图模型连接到视图:

  • ObservableObject 与 @Published 会发出变化通知
  • @StateObject 创建并拥有视图模型
  • @ObservedObject 观察一个传入的视图模型
  • @MainActor 让异步更新保持在主线程上

建立响应式绑定后,视图始终会自动反映视图模型的最新状态。

常见问题解答

「将视图模型绑定到视图」课时是免费的吗?

是的 — 「将视图模型绑定到视图」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「将视图模型绑定到视图」这节课中我会学到什么?

使用 SwiftUI 和 Combine 连接视图模型。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「将视图模型绑定到视图」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. MVVM 模式
  2. 将视图模型绑定到视图
  3. 协调器模式
  4. 测试视图模型
← 返回 Swift Academy