SwiftUI如何在不同TabView页面间共享UserViewModel的用户数据?
最优实现方案
核心思路是将唯一的UserViewModel实例通过EnvironmentObject注入到整个视图树中,所有需要使用用户数据的视图直接从环境中读取该实例,利用@Published的特性自动实现跨视图的状态同步,完全替代手动读写UserDefaults的实现。该方案符合SwiftUI单向数据流设计规范,无需手动处理状态同步,用户数据更新后所有关联视图会自动刷新。
步骤1:修改ContentView,持有并注入全局UserViewModel
struct ContentView: View { enum AppPage: Int { case TabA=0, TabB=1 } @StateObject var settings = Settings() // 用@StateObject持有UserViewModel,生命周期和ContentView绑定 @StateObject var userViewModel = UserViewModel() var body: some View { NavigationView { TabView(selection: $settings.tabItem) { TabAView() // 不再需要手动传viewModel .tabItem { Text("TabA") } .tag(AppPage.TabA) TabBView() // 原AppsView对应TabBView,可按需调整命名 .tabItem { Text("Apps") } .tag(AppPage.TabB) } .accentColor(.white) .edgesIgnoringSafeArea(.top) .onAppear(perform: { settings.tabItem = .TabA }) .navigationBarTitleDisplayMode(.inline) } .environmentObject(settings) // 注入UserViewModel到整个视图树,所有子视图都可直接读取 .environmentObject(userViewModel) } }
步骤2:修改TabAView,从环境读取UserViewModel
struct TabAView: View { // 直接从环境获取实例,不需要外部传参 @EnvironmentObject var userViewModel: UserViewModel @EnvironmentObject var settings: Settings var body: some View { VStack { // 直接使用userViewModel.user即可,变更会自动刷新视图 if let user = userViewModel.user { Text(user.name) // 示例用法 } } .onAppear(perform: { // 如果需要每次进入都刷新用户数据,可以在这里调用userViewModel.getUserProfile() }) } }
步骤3:修改TabBView,移除UserDefaults读写逻辑
struct TabBView: View { @EnvironmentObject var userViewModel: UserViewModel var body: some View { VStack (spacing: 10) { // 不需要手动传递user,子视图直接读取环境即可 UserSearch(comingFromAppsSection: true) } } }
步骤4:修改UserSearch,自动响应数据变更
struct UserSearch: View { @EnvironmentObject var userViewModel: UserViewModel private let comingFromAppsSection: Bool init(comingFromAppsSection: Bool) { self.comingFromAppsSection = comingFromAppsSection // 完全删除读UserDefaults的逻辑 } var body: some View { VStack { // user变更时会自动刷新Text显示 Text(userViewModel.user?.status ?? "未获取到用户状态") } } }
可选优化:保留用户数据持久化能力
如果需要APP冷启动后优先读取缓存的用户数据,可以在UserViewModel中增加缓存读写逻辑,不会影响原有响应式特性:
class UserViewModel: ObservableObject { private var apiService = APIService.shared @Published var user: EndUserData? init () { // 启动时先读本地缓存 if let cacheData = UserDefaults.standard.data(forKey: "Account") { do { let responseData = try JSONDecoder().decode(ResponseData<EndUserData>.self, from: cacheData) self.user = responseData.data } catch { print("缓存解析失败: \(error)") } } // 再请求最新用户数据 getUserProfile() } func getUserProfile() { apiService.getUserAccount() { [weak self] user in guard let self = self else { return } DispatchQueue.main.async { self.user = user // 数据更新时自动更新本地缓存 if let user = user { do { let data = try JSONEncoder().encode(ResponseData(data: user)) UserDefaults.standard.set(data, forKey: "Account") } catch { print("缓存写入失败: \(error)") } } } } } }
完成后可同步删除APIService的getUserAccount方法中写UserDefaults的冗余逻辑。
内容的提问来源于stack exchange,提问作者user1960279
相关产品推荐
相关产品推荐

