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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 08:09:00