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

子类中@Published属性包装器失效问题求助

SwiftUI中继承父类的ObservableObject子类在视图重建后@Published失效问题

我有一个继承自DashboardTradableViewModel的子类DashboardWatchlistViewModel,该子类实现了ObservableObject协议,内部包含@Published修饰的isHighlighted和chartViewModel字段。这个模型对应的DashboardWatchlistView用于单元格中,首次创建视图时@Published能正常触发视图更新,但当单元格因数据更新频繁重建视图并传入新模型实例后,@Published就不再生效(比如高亮功能失效)。移除继承关系后,所有功能恢复正常。

我曾找到过类似的SwiftUI Bug相关问题,尝试调用self.objectWillChange.send()方法也没能解决问题。

相关代码

模型代码

final class DashboardWatchlistViewModel: DashboardTradableViewModel, ObservableObject {
    
    @Published var isHighlighted = false
    @Published var chartViewModel: AssetLineChartViewRepresentable.ViewModel?

    ........

    init(.....) {
         super.init()
    }
}

父模型代码

class DashboardTradableViewModel {
    // MARK: - Properties

    // MARK: - Init
    init(....) {

    }
}

视图创建代码(频繁调用)

func configure(with viewModel: DashboardWatchlistViewModel) {
    print("Tag1 configure")
    self.dashboardWatchlistView = DashboardWatchlistView(viewModel: viewModel)
    self.viewModel = viewModel

    viewModel.chartDataEvent.compactMap { $0 }
        .receive(on: DispatchQueue.main)
        .sink { [weak self] chartData in
            viewModel.chartViewModel = AssetLineChartViewRepresentable.ViewModel(chartData: chartData, percentageChange: viewModel.percentageChange2)
        }
        .store(in: &cancellables)
}

视图代码

struct DashboardWatchlistView: View {

    private struct Layout {
        static let imageHeight: CGFloat = 40
        static let imageWidth: CGFloat = 40
        static let topPadding: CGFloat = 10
        static let frameHeight: CGFloat = 69
        static let cornerRadius: CGFloat = 9
        static let scaleFactor: CGFloat = 1.0
    }

    @ObservedObject var viewModel: DashboardWatchlistViewModel

    var body: some View {
        VStack(alignment: .center) {
            ZStack {
                HStack(spacing: .designSystem(.extraSmall4)) {
                    HStack(spacing: .designSystem(.small)) {
                        KFImage(viewModel.logoURL)
                            .serialize(by: SVGCacheSerializer())
                            .setProcessor(SVGProcessor())
                            .scaleFactor(Layout.scaleFactor)
                            .resizable()
                            .placeholder {
                                Circle()
                                    .fill(Color(viewModel.placeholderColor.isEmpty ? .gray : UIColor(hex: viewModel.placeholderColor)))
                            }
                            .frame(width: Layout.imageWidth, height: Layout.imageHeight)
                            .clipShape(RoundedRectangle(cornerRadius: Layout.imageWidth / 2))
                            .overlay(RoundedRectangle(cornerRadius: Layout.imageWidth / 2).stroke(.white, lineWidth: 2 / UIScreen.main.scale))

                        VStack(alignment: .leading, spacing: .designSystem(.extraSmall3)) {
                            HStack {
                                Text(viewModel.leftTitle).font(.subheadline).fontWeight(.semibold).lineLimit(1)
                            }
                            Text(viewModel.leftSubtitle).font(.caption2).foregroundColor(Color(ThemeManager.current.neutral50))
                        }
                    }

                    Spacer()

                    if let chartViewModel = viewModel.chartViewModel {
                        AssetLineChartViewRepresentable(viewModel: chartViewModel).frame(width: 65, height: 20)
                    }

                    VStack(alignment: .trailing, spacing: .designSystem(.extraSmall3)) {
                        percentChangeView(assetPercentChangeType: viewModel.assetPercentChangeType)
                        Text(viewModel.rightSubtitle).font(.caption2).foregroundColor(Color(ThemeManager.current.neutral50))
                    }
                    .padding(.leading, .designSystem(.medium))
                }

                .padding([.leading, .trailing])

                if !viewModel.hideSeparator {
                    VStack {
                        Spacer()
                        Divider().padding(.leading)
                    }
                }
            }
        }
        .frame(height: Layout.frameHeight)
        .background(
            backgroundView(assetPositionType: viewModel.corners)
        )
    }
}

问题演示

问题演示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:45:34