SwiftUI应用未随UserSessionManager状态变化更新的问题排查
问题根源
你的核心问题在于依赖容器DependencyContainer没有转发UserSessionManager的状态变化通知。
虽然UserSessionManager本身是ObservableObject且标记了@Published属性,但DependencyContainer作为被注入的环境对象,并不会自动监听其内部sessionManager的变化。当sessionManager的authenticationState改变时,DependencyContainer没有发送objectWillChange事件,导致SwiftUI的ContentView无法感知到状态更新,自然不会刷新UI。
解决方案
以下是三种可行的修复方案,你可以根据项目架构选择:
方案一:让依赖容器转发SessionManager的变化通知
这种方案保持现有依赖注入结构,通过Combine转发sessionManager的变化事件:
- 首先修改
UserSessionManagerProtocol,让它继承ObservableObject:
protocol UserSessionManagerProtocol: ObservableObject { var authenticationState: AuthenticationState { get } var currentUser: User? { get } // 保留其他协议方法 }
- 更新
DependencyContainer,添加Combine订阅来转发事件:
class DependencyContainer: ObservableObject { let apiService: any APIServiceProtocol let authService: any AuthenticationServiceProtocol let userService: any UserServiceProtocol let sessionManager: any UserSessionManagerProtocol private var cancellables = Set<AnyCancellable>() init() { apiService = APIService() authService = AuthenticationService(apiService: apiService) userService = UserService(apiService: apiService) sessionManager = UserSessionManager(authService: authService, userService: userService) apiService.setTokenProvider(sessionManager) // 转发sessionManager的状态变化通知 sessionManager.objectWillChange .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellables) } }
方案二:直接将SessionManager作为独立环境对象注入
跳过依赖容器的中转,直接把sessionManager注入环境,让ContentView直接监听它的变化:
- 修改App初始化代码:
@main struct GatherApp: App { @StateObject var container = DependencyContainer() var body: some Scene { WindowGroup { ContentView() .environmentObject(container) .environmentObject(container.sessionManager as UserSessionManager) } } }
- 更新
ContentView直接使用sessionManager环境对象:
struct ContentView: View { @EnvironmentObject var container: DependencyContainer @EnvironmentObject var sessionManager: UserSessionManager var body: some View { VStack { Group { switch sessionManager.authenticationState { case .initial: ProgressView { Text("Loading...") } case .unauthenticated: LandingView() case .authenticated(let signupStep): if signupStep == .completed { HomeView() } else { SignUpFlow(currentStep: signupStep) } } } } } }
方案三:将SessionManager标记为@Published属性
如果你的项目允许,直接把sessionManager改为@Published属性,让DependencyContainer自动监听它的变化:
class DependencyContainer: ObservableObject { let apiService: any APIServiceProtocol let authService: any AuthenticationServiceProtocol let userService: any UserServiceProtocol @Published var sessionManager: any UserSessionManagerProtocol init() { apiService = APIService() authService = AuthenticationService(apiService: apiService) userService = UserService(apiService: apiService) sessionManager = UserSessionManager(authService: authService, userService: userService) apiService.setTokenProvider(sessionManager) } }
验证要点
- 确保
UserSessionManagerProtocol继承了ObservableObject(方案一、三需要) - 检查Combine订阅是否正确保留在
cancellables集合中(方案一) - 确认类型转换
as UserSessionManager不会引发类型错误(方案二)
内容的提问来源于stack exchange,提问作者AlePouroullis
相关产品推荐
相关产品推荐

