1

I am using Core data and Swiftui and everything have been working fine but in this one view I have a List, ForEach that is not working.

So for testing purpose my code currently look like this:


@ObservedObject var viewModel = NewLearningWhyViewModel()

VStack {
    ForEach(viewModel.whys, id: \.self) { why in
        Text(why.why)
    }
            
    List {
        ForEach(viewModel.whys, id: \.self) { why in
            Text(why.why)
        }
    }
           
    Button(action: {
        viewModel.createWhy(why: "Test", count: viewModel.whys.count, learning: learn)
        viewModel.fetchWhy(predicate: NSPredicate(format: "parentLearning == %@", learn))
    }){
        Text("Add")
            .font(.title)
            .foregroundColor(.white)
    }
}            

The problem is my List { ForEach, first time I press add button it shows the new why, second time i press the button the whole list goes away, the third time I press the button the list shows again with all 3 items.

To test the problem I added that first ForEach part and that shows the correct item at all times, so there is not a problem with the viewmodel or adding the items, the items are added and it is published from the viewmodel since that part is updated.

Does anyone have any clue why my List { ForEach only show every other time?

jrturton
  • 118,105
  • 32
  • 252
  • 268
Peter
  • 37
  • 7
  • 1
    Without a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) it is impossible to help you troubleshoot. – lorem ipsum Apr 23 '21 at 11:28
  • 1
    In my experience, putting a List inside of a VStack can sometimes cause weird behavior. Some things you could try: 1) Setting the frame of your VStack to have a maxWidth and maxHeight of .infinity and putting the "scaleToFill()" modifier on your List. 2) Adding the .id(UUID()) modifier to your List or, if that doesn't help, to your ForEach. You could also try a LazyVStack w/a pinned view for the Button, if you don't need List behavior like deleting and re-ordering. – Becky Hansmeyer Apr 23 '21 at 15:27

3 Answers3

1

I have gotten this problem. I figure it out by adding objectWillChange in ViewModel, and send() it manually when your why is changed. Actually I don't know your NewLearningWhyViewModel clearly, so this is just an example, you should try it out.

class NewLearningWhyViewModel: ObservableObject {
    let objectWillChange: ObservableObjectPublisher = ObservableObjectPublisher()
    @Published var whys: Why = Why() {
        didSet {
            objectWillChange.send()
        }
    }
}
Ho Si Tuan
  • 520
  • 3
  • 13
0

Ok the post from Becky Hansmeyer solved it, adding .id(UUID()) to the list solved it and it started working correctly...

Peter
  • 37
  • 7
0

because of "viewModel.whys" is set of classes.

SwiftUI does not work with classes directly.

There is 2 solutions:

  1. make it struct instead of class + add @Published modifier inside of view
  2. leave it as is + do it observable object and in init of your view assign into observed object.

More details here:

https://stackoverflow.com/a/62919526/4423545

Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101