4

I'm using a ForEach to loop through an array of saved user input and display those, which displays everything correctly, unless I add a new input to this array, then the new item isn't displayed unless I navigate to another View then come back.

I've tried everything, from changing .id with .self, but nothing works.

Any idea guys? Thank you!

EDIT: It looks like it's my sheet that prevents my view from updating, I've tried simply adding the sheet code in my view and now the ForEach updates in real time, is there something I'm missing regarding how sheets could get in the way?

struct AnswersView: View {
@EnvironmentObject var vm: BrainstormViewModel
@Environment(\.presentationMode) var presentationMode
@State var mBIndex: Int
@State var substitute: [String] = []
@State var showSheet: Bool = false
@State var updater: Bool = false
var body: some View {
    ScrollView {
        VStack(alignment: .leading) {
            Text("How could I...")
            Text(vm.brainstormArray[mBIndex].title)
                .font(.system(size: 32, weight: .bold, design: .rounded))
                .multilineTextAlignment(.leading)
            Button {
                showSheet.toggle()
            } label: {
                ButtonSubview(icon: "play.fill", text: "Continue brainstorm")
                    .environmentObject(BrainstormViewModel())
            }

            ForEach(vm.brainstormArray[mBIndex].answersArray, id: \.self) { index in

                Text(index.name)
                    .font(.system(size: 20, weight: .bold, design: .rounded))
                    .padding(.top, 30)
                HStack {
                    Text(index.answer[0])

                        .padding()

                    Spacer()
                }

                .background(Color.MyTheme.orangeLight)
                .cornerRadius(16)
            }
        }

        .fullScreenCover(isPresented: $showSheet) {
            BrainstormView(mBIndex: mBIndex)
        }

        .navigationBarTitleDisplayMode(.inline)
    }
    .frame(maxWidth: .infinity)
    .padding()
    .background(Color.white)
}

}

2
  • 1
    Without a minimal reproducible example, this is likely to be difficult if not impossible to debug. There are lots of missing types here that your code depends on. Commented Mar 14, 2022 at 18:36
  • Your View is way too big, you have too many @States. id: \.self is a mistake, ForEach works with Identifiable data you need to edit your model data struct to conform to that. Also we don't use view model objects in SwiftUI but yours actually looks like the model which is fine. Commented Mar 14, 2022 at 22:40

2 Answers 2

8

wherever you change the data, insert:

vm.objectWillChange.send()
Sign up to request clarification or add additional context in comments.

Comments

-1

The possible solution - but you have to try it in your code - is to make a @State variable that contains your array, and make that array a @Published variable in the view model. Then, listen to changes in that array and update the @State variable of your view.

Here's the idea:

In the view model:

class BrainstormViewModel: ObservableObject {
    ...
    @Published private(set) var brainstormArray: [WhateverType]
    ...
}

In the view (scroll also to the bottom):

struct AnswersView: View {
@EnvironmentObject var vm: BrainstormViewModel
@Environment(\.presentationMode) var presentationMode
@State var mBIndex: Int
@State var substitute: [String] = []
@State var showSheet: Bool = false
@State var updater: Bool = false

// Here is the new variable
@State private var viewArray = [WhateverType]()

var body: some View {
    ScrollView {
        VStack(alignment: .leading) {
            Text("How could I...")
            Text(vm.brainstormArray[mBIndex].title)
                .font(.system(size: 32, weight: .bold, design: .rounded))
                .multilineTextAlignment(.leading)
            Button {
                showSheet.toggle()
            } label: {
                ButtonSubview(icon: "play.fill", text: "Continue brainstorm")
                    .environmentObject(BrainstormViewModel())
            }


            // Change the array over which the ForEach iterates, use the view variable
            ForEach(viewArray[mBIndex].answersArray, id: \.self) { index in

                Text(index.name)
                    .font(.system(size: 20, weight: .bold, design: .rounded))
                    .padding(.top, 30)
                HStack {
                    Text(index.answer[0])

                        .padding()

                    Spacer()
                }

                .background(Color.MyTheme.orangeLight)
                .cornerRadius(16)
            }
        }

        .fullScreenCover(isPresented: $showSheet) {
            BrainstormView(mBIndex: mBIndex)
        }

        .navigationBarTitleDisplayMode(.inline)
    }
    .frame(maxWidth: .infinity)
    .padding()
    .background(Color.white)

    // Initialise the state variable
    .onAppear {
        viewArray = vm.brainstormArray
    }

    // Listen to changes in the view model
    .onChange(of: vm.brainstormArray) { array in
        viewArray = array
    }
}

1 Comment

Nope, it's still not updating when the sheet is dismissed, I have to navigate to another view to update the Foreach loop... =/

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.