1

I have a LazyVStack presenting Cells. My main View which has the LazyVStack has a viewModel.

@StateObject private var model = ViewModel()

The Stack presents a list of CustomViews.

LazyVStack {
    ForEach(model.items) { item in
       CustomView(item: item)
    }
}

Each custom view consists from two other subviews, CustomView1 and CustomView2. CustomView2 has a button, where onTap I want to flip the cell.

However at that point my Custom views have a new copy of these items (struct). What is the best approach to point back to the model to achieve:

.onTapGesture {
   model.flipItem(item)
}
  • Somehow multiple @Binding variables is an option ?
  • Making the ViewModel shared singleton for easy access ?
  • Better option ?
PoolHallJunkie
  • 1,345
  • 14
  • 33
  • Look at `EnvironmentObject` that is how you share a `StateObject` https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app – lorem ipsum May 22 '21 at 16:22

1 Answers1

1

I would add a property inside your Item struct that stores if the card is flipped or not:

struct Item {
    var ifFlipped = false
    ...
}
model.items = [Item(), Item()]

Then loop over model.items.indices, so that you can get the Binding:

LazyVStack {
    ForEach(model.items.indices, id: \.self) { index in
       CustomView(item: $model.items[index]) /// this will be a Binding<Item>
    }
}

And your CustomView/CustomView1 will need to look something like this.

struct CustomView: View {
    @Binding var item: Item
    
    var body: some View {
        CustomView1(item: $item) /// pass Binding down
    }
}

struct CustomView1: View {
    @Binding var item: Item
    
    var body: some View {
        Text("Hi")
            .onTapGesture {
                item.isFlipped.toggle()
            }
    }
}
aheze
  • 24,434
  • 8
  • 68
  • 125
  • That is a good suggestion. What if the button is further down the line ? Would I have to ExtractViews only once ? – PoolHallJunkie May 22 '21 at 16:19
  • 1
    @PoolHallJunkie just keep passing the `Binding` down (see my edit). But what do you mean by "ExtractViews"? – aheze May 22 '21 at 16:23
  • I see a couple of problems with this solution. Can't pass the model as its a StateObject. But by passing the item itself it means that I have to remove any private properties from my viewModel and allow external functions to edit my items. – PoolHallJunkie May 22 '21 at 17:02
  • @PoolHallJunkie I think technically you can pass the model via `@ObservedObject` instead of `@Binding`, but why would you want that? And how come you need to remove private properties from your viewModel? – aheze May 22 '21 at 18:14
  • If my model items are private(set), I can't pass them as $model.items[index] because the model will not be mutable. I made it work but I am changing the model from the CustomView struct instead of inside the ModelView. – PoolHallJunkie May 22 '21 at 18:26
  • @PoolHallJunkie ah, I see. – aheze May 22 '21 at 18:28
  • `@Binding` will not work with a `private(set)` because it is a two-way connection. The only option is to somehow pass your `StateObject` You can use the singleton or `@EnvironmentObject`. – lorem ipsum May 22 '21 at 18:50