SwiftUI MVVM模式下嵌套领域模型数据处理与视图模型边界问题咨询
问题解答
1. 视图模型设计方案
你的猜测是正确的,更推荐每个视图对应独立专属视图模型 + 根领域模型通过EnvironmentObject注入导航栈的方案,不推荐全流程共用单个视图模型:
- 逻辑按视图边界隔离,每个视图模型只负责当前视图的交互逻辑,避免单个视图模型承载过多跨场景逻辑,后续迭代维护成本更低
- 不同层级的视图只需要关注自己要修改的领域属性:
- 巴士信息编辑页对应
BusEditViewModel,仅处理巴士名称修改逻辑 - 司机列表页对应
DriverListViewModel,仅处理司机新增、删除、跳转详情逻辑 - 司机详情编辑页对应
DriverEditViewModel,仅处理司机姓名修改、行程列表操作逻辑 - 行程编辑页对应
TourEditViewModel,仅处理行程星期配置修改逻辑
- 巴士信息编辑页对应
- 后续替换为Core Data方案时,只需要把领域模型替换为
NSManagedObject子类,上层视图模型的操作逻辑基本不需要调整,迁移成本极低。
2. 嵌套模型变更不触发视图刷新问题
这个问题的核心原因是@Published仅会在属性本身的值/引用发生变更时发送通知,你用class类型作为嵌套模型,修改内部属性时属性的引用没有变化,因此不会触发上层视图模型的变更通知,两种可落地的解决方案如下:
方案1:Combine链式监听嵌套变更(适合需要全局感知全量变更的场景)
所有领域模型遵守ObservableObject协议,内部可变属性加@Published修饰,在根视图模型中通过Combine链式监听所有嵌套层级的变更,手动触发根视图模型的变更通知:
import Combine // 调整后的领域模型示例 class DriverModel: Identifiable, ObservableObject { let id: UUID @Published var firstName: String @Published var lastName: String @Published var toursToDrive: [TourToDriveModel] // 初始化逻辑省略 } // TourToDriveModel 同理遵守ObservableObject,可变属性加@Published // 根视图模型监听逻辑 class AlterBusViewModel: ObservableObject { @Published var bus: BusModel private var cancellables = Set<AnyCancellable>() init(bus: BusModel) { self.bus = bus // 监听所有司机的变更 bus.$drivers .flatMap { $0.map { $0.objectWillChange }.publisher } .flatMap { $0 } .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellables) // 监听所有司机关联行程的变更 bus.$drivers .flatMap { $0.map { $0.$toursToDrive }.publisher } .flatMap { $0 } .flatMap { $0.map { $0.objectWillChange }.publisher } .flatMap { $0 } .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellables) } }
方案2:子视图直接绑定领域属性(更轻量化)
如果父视图不需要实时感知深层嵌套属性的变更,子视图可以直接用@Bindable(SwiftUI 4+支持)修饰传入的领域模型实例,直接绑定属性做修改,子视图会自动刷新,不需要向上层抛变更通知,代码更简洁。
Core Data适配提示
Core Data的NSManagedObject本身默认实现ObservableObject协议,所有@NSManaged属性变更都会自动触发objectWillChange通知,上述两种方案后续迁移到Core Data时基本不需要修改逻辑,只需要调整领域模型的父类即可。
内容的提问来源于stack exchange,提问作者andreas.teich
相关产品推荐
相关产品推荐

