SwiftUI中View未响应链式ObservedObject的Published属性变更如何解决
问题根因
@ObservedObject 是 SwiftUI 专用的属性修饰符,仅能在 SwiftUI 视图结构体中生效,你在作为 ObservableObject 的 ViewModel 中使用它不会产生任何监听效果。ObservableObject 默认只会对自身被 @Published 修饰的属性变更发送通知,嵌套的 ObservableObject(你代码里的 AuthenticationService)的属性变更不会自动向上冒泡触发上层 ViewModel 的通知,因此视图收不到刷新信号。
可选解决方案
方案1:直接在视图层监听服务(改动最小)
直接把 AuthenticationService 放到视图层作为 @ObservedObject,跳过 ViewModel 的中转,服务的 user 属性变更会直接触发视图刷新:
struct WelcomeView: View { // 直接监听服务 @ObservedObject private var authenticationService: AuthenticationService @State private var signInActive: Bool = false init(authenticationService: AuthenticationService) { self.authenticationService = authenticationService } var body: some View { if authenticationService.user != nil { HomeView() } else { LoginView() } } }
方案2:ViewModel 手动转发变更(保留现有层级)
如果需要保留 View->ViewModel->Service 的架构分层,可在 ViewModel 中通过 Combine 监听服务的变更,手动触发自身的通知:
import Combine extension WelcomeView { final class Model: ObservableObject { var authenticationService: AuthenticationService // 存储订阅关系 private var cancellable = Set<AnyCancellable>() init(authenticationService: AuthenticationService) { self.authenticationService = authenticationService // 监听服务的变更,转发给当前 ViewModel authenticationService.objectWillChange .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellable) } } }
方案3:ViewModel 封装用户状态(更符合 MVVM 封装原则)
不把服务直接暴露给视图,在 ViewModel 中新增 @Published 修饰的用户状态属性,中转服务的用户变更,视图只需要和 ViewModel 的属性交互:
import Combine extension WelcomeView { final class Model: ObservableObject { @Published var currentUser: User? private var authenticationService: AuthenticationService private var cancellable = Set<AnyCancellable>() init(authenticationService: AuthenticationService) { self.authenticationService = authenticationService // 中转服务的user属性变更 authenticationService.$user .receive(on: DispatchQueue.main) .assign(to: &$currentUser) } } }
对应的视图代码调整为读取 ViewModel 的 currentUser 属性:
var body: some View { if viewModel.currentUser != nil { HomeView() } else { LoginView() } }
额外优化建议
如果你最低支持 iOS 14 及以上版本,视图中对 ViewModel 的引用建议替换为 @StateObject 而非 @ObservedObject,避免视图意外刷新时 ViewModel 被重复创建导致的异常问题。
内容的提问来源于stack exchange,提问作者Parth Adroja

