You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI MVVM架构下如何获取Model到View的Binding

问题根因

首先你贴的代码存在几处命名笔误:ViewModel中定义的模型变量是myModel,赋值时却写了splitModel;Model中定义的字段是testData,视图层却访问了不存在的amount字段,这类书写错误先修正再谈逻辑问题。
核心报错和架构设计无关:SwiftUI中TextField的value参数要求传入Binding<Value>类型的双向绑定,你直接传入viewModel.xxx拿到的是只读的普通值,自然无法编译。不需要把业务数据挪到视图层的@State里,这种做法确实破坏分层,你只是没掌握MVVM架构下获取双向绑定的正确方式。

正确实现方案

第一步:统一各层命名,修正笔误

Model层统一字段名:

import Foundation

struct MyModel {
    var amount: Double
}

ViewModel层修正变量名,保留业务处理方法:

import Foundation
import SwiftUI

class MyViewModel: ObservableObject {
    @Published var myModel = MyModel(amount: 0)

    func setAmount(_ newVal: Double) {
        // 这里可以写业务校验逻辑,比如金额不能为负、精度截断等,完全符合VM承接业务逻辑的分层要求
        guard newVal >= 0 else { return }
        myModel.amount = newVal
    }
}

第二步:视图层正确传入双向绑定

根据业务场景选一种写法即可,两种写法都不会破坏分层:

  • 场景1:不需要额外校验逻辑,输入值直接同步到模型
    直接通过$前缀获取@Published属性的投影绑定,这是最常用的写法:

    struct ContentView: View {
        @ObservedObject var viewModel = MyViewModel()
    
        var body: some View {
            NavigationView {
                Form {
                    Section {
                        TextField("请输入金额",
                                  value: $viewModel.myModel.amount,
                                  format: .currency(code: "USD"))
                    }
                }
            }
        }
    }
    

    这种方式生成的绑定会自动双向同步:用户输入的内容会直接修改ViewModel中的模型值,ViewModel中模型值变化也会自动驱动视图刷新,数据始终存在ViewModel层,View只负责交互和展示。

  • 场景2:需要在值修改时执行ViewModel中的自定义业务逻辑(比如校验、触发其他关联操作)
    手动构造自定义Binding,把赋值逻辑指向ViewModel的业务方法:

    struct ContentView: View {
        @ObservedObject var viewModel = MyViewModel()
    
        private var amountBinding: Binding<Double> {
            Binding(
                get: { viewModel.myModel.amount },
                set: { viewModel.setAmount($0) }
            )
        }
    
        var body: some View {
            NavigationView {
                Form {
                    Section {
                        TextField("请输入金额",
                                  value: amountBinding,
                                  format: .currency(code: "USD"))
                    }
                }
            }
        }
    }
    
概念偏差纠正
  • @State仅适合存储View本地的、非业务相关的纯界面状态(比如弹窗是否展示、页面滚动偏移量),业务数据必须放在ViewModel层,这是MVVM的核心原则,不需要为了过编译打破这个规则。
  • 遵循ObservableObject协议的ViewModel,其内部用@Published标记的属性,在View中可以通过$前缀直接拿到合法的Binding类型值,完全满足系统组件的双向绑定要求,不需要额外做转换。
  • 写代码时要保证变量名、字段名前后一致,很多低级编译错误都是命名不统一导致的,和架构设计无关。

内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:51:27