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

SwiftUI中如何让多个ViewModel共享同一数据源?

SwiftUI 共享数据控制器的非单例方案

问题核心

你当前的问题很明确:每个视图都手动实例化了独立的UserController,导致不同ViewModel持有不同的控制器实例,修改数据后自然无法在多个视图间同步。要解决这个问题,关键是让所有ViewModel共享同一个UserController实例,同时避开单例的耦合性高、难以测试等弊端。

可行解决方案

方案一:依赖注入 + SwiftUI 环境对象(推荐)

这是SwiftUI框架原生支持的方式,符合其设计理念,能优雅实现全局实例共享:

  1. 在App入口创建唯一的UserController实例,并注入到全局环境中
@main
struct YourApp: App {
    // 创建全局唯一的UserController实例
    private let userController = UserController()
    
    var body: some Scene {
        WindowGroup {
            TabView {
                HomeView()
                SettingsView()
            }
            // 将控制器注入到环境,让所有子视图可访问
            .environment(userController)
        }
    }
}
  1. 修改视图,从环境中获取共享实例并初始化ViewModel
struct HomeView: View {
    // 从环境中拿到共享的UserController
    @Environment(UserController.self) private var userController
    @State private var vm: HomeViewModel!
    
    var body: some View {
        VStack {
            if let userProfile = vm.controller.userProfile {
                Text("\(userProfile.username)")
            }
            
            Button("Get data") {
                Task {
                    await vm.getData()
                }
            }
            
            Button("Update username") {
                vm.updateUsername(newUsername: "HomeViewUsername")
            }
        }
        .onAppear {
            // 用环境中的共享实例初始化ViewModel
            vm = HomeViewModel(controller: userController)
        }
    }
}

SettingsView做同样修改即可,这样两个ViewModel就会共用同一个UserController实例,数据变化会自动同步到所有视图。

方案二:依赖注入容器(适合复杂应用)

如果你的应用规模较大,需要管理多个共享服务,可以创建一个统一的依赖容器,集中管理所有实例:

// 依赖容器,统一管理全局共享服务
final class DIContainer {
    static let shared = DIContainer()
    
    // 全局唯一的UserController实例
    let userController: UserController
    
    private init() {
        self.userController = UserController()
    }
}

然后在视图中直接从容器获取实例初始化ViewModel:

struct HomeView: View {
    @State private var vm = HomeViewModel(controller: DIContainer.shared.userController)
    
    // 其余代码不变
}

这个方案比单例灵活,测试时可以轻松替换容器中的实例做Mock,避免单例带来的测试困难。

方案三:SwiftData(适合需要持久化的场景)

如果UserProfile需要持久化存储,直接用SwiftData管理数据即可。所有ViewModel通过同一个数据上下文访问数据,天然实现多视图数据同步,无需额外维护控制器:

// 定义UserProfile模型
@Model
class UserProfile {
    var username: String
    
    init(username: String) {
        self.username = username
    }
}

在App入口配置SwiftData:

@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            TabView {
                HomeView()
                SettingsView()
            }
            .modelContainer(for: UserProfile.self)
        }
    }
}

ViewModel中直接通过数据上下文操作数据,所有视图会自动同步变化。

总结

  • 环境对象+依赖注入是SwiftUI中最常用的轻量方案,符合框架设计
  • 依赖容器适合复杂应用,便于管理多个共享服务和测试
  • SwiftData适合需要持久化数据的场景,天然实现数据同步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 19:03:18