0

I have a model that inherits from another one. In the model, I have a few @Published fields. The view where the model is getting used is used in a cell. The first time I create the view @Published works fine. But the cell gets updated often with new data so I need to recreate the view with a new model. And here I have a problem. @Published stops working (for instance highlighting on the video). And everything works fine if I get rid of the inheritance.

I found a similar issue (that was a SwiftUI bug) and also tried to use self.objectWillChange.send() but it did not help.

Model:

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

    ........

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

Parent model:

class DashboardTradableViewModel {
    // MARK: - Properties

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

    }
}

Creating the view(this part is getting called frequently):

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)
}

View:

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)
        )
    }
}

enter image description here

Artiom
  • 513
  • 1
  • 4
  • 15
  • hi, interesting, might be related https://stackoverflow.com/questions/57615920/published-property-wrapper-not-working-on-subclass-of-observableobject – jspcal Sep 22 '22 at 19:30
  • yes, I mentioned it in the description – Artiom Sep 22 '22 at 19:33
  • SwiftUI was designed to prevent having these consistency problems typical of objects, I recommend learning SwiftUI's @Binding instead of using multiple objects. Regarding model data, in SwiftUI usually we only have a single store object (usually an environmentObject) that holds the array of model structs. – malhal Sep 26 '22 at 16:36

0 Answers0