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

SwiftUI中点击按钮后ProgressView不显示的问题排查

问题原因

核心问题是嵌套的ObservableObject属性变化无法触发外层ObservableObject的更新通知:

  • User类中用@Published修饰的credentials是Login类型(本身也是ObservableObject),但@Published仅会在credentials这个对象的引用被替换时(比如重新赋值user.credentials = Login())发送更新通知。
  • 当修改credentials内部的showLoginProgress时,Login自身的objectWillChange会触发,但User的objectWillChange不会同步触发,导致依赖User的LoginView无法感知到内部属性变化,因此不会刷新显示ProgressView。
解决方案

以下三种修复方式可根据实际场景选择:

方案1:将Login改为值类型(struct)

这是SwiftUI的推荐实践,值类型的属性变化会自动触发@Published的更新:

// 把Login从class改为struct,无需继承ObservableObject
struct Login {
    var showLoginProgress: Bool = false
}

class User: ObservableObject {
    @Published var credentials = Login()
}

此时修改user.credentials.showLoginProgress = true时,由于struct是值类型,credentials会被视为整体变化,User的@Published会发送通知,LoginView就能正常刷新。

方案2:让User监听Login的变化

若必须保留Login为class(比如有其他业务需求),可让User手动订阅Login的objectWillChange事件,转发给自己的objectWillChange:

import Combine

class User: ObservableObject {
    var credentials = Login()
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        // 订阅Login的变化,转发给User的objectWillChange
        credentials.objectWillChange
            .sink(receiveValue: { [weak self] _ in
                self?.objectWillChange.send()
            })
            .store(in: &cancellables)
    }
}

class Login: ObservableObject {
    @Published var showLoginProgress: Bool = false
}

这样当Login内部属性变化时,User会同步发送更新通知,触发View刷新。

方案3:在User中直接转发属性

如果仅需监听showLoginProgress这一个属性,可在User中直接定义对应的@Published属性,转发Login的属性:

import Combine

class User: ObservableObject {
    var credentials = Login()
    @Published var showLoginProgress: Bool {
        get { credentials.showLoginProgress }
        set { credentials.showLoginProgress = newValue }
    }
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        // 监听Login的属性变化,同步到User的属性
        credentials.$showLoginProgress
            .assign(to: \.showLoginProgress, on: self)
            .store(in: &cancellables)
    }
}

之后在LoginView中直接使用user.showLoginProgress即可:

if user.showLoginProgress {
    ProgressView()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:54:22