skip to Main Content

I can’t understand why my array (which I checked to ensure it isn’t empty) is not being passed through to a view correctly.

ContentView receives the set of questions from MenuView, and once assigned to contentSelectedSet, I checked to make sure the two sets contained the correct information, which they do. The entire set of questions as I would expect is there. However, in the .fullScreenCover modifier, the set is not passed to DebugQuizView and will only take me to that else text. If I don’t use the if/else block the app crashes.

I don’t think the issue would be with MenuView passing in the array, because I have verified with the print statements that the value passed is correct, but I could have always missed something.

Further, I have tried directly passing in one of the quiz question arrays itself (avoiding the dependency on MenuView), and continue to run into the same problem.

struct ContentView: View {
    @State private var isQuizViewShowing = false
//    @State var contentQuizTitle = ""
    @State var contentSelectedSet: [Question]?
    @State var hasSelectedSet = false

    var body: some View {
        TabView {
            MenuView(onQuizButtonTapped: { menuSelectedSet in
                contentSelectedSet = menuSelectedSet
                hasSelectedSet = true
                print("The content set is (String(describing: contentSelectedSet))")
                print("The selected set is (menuSelectedSet)")
                isQuizViewShowing = true})
                .tabItem {
                    Image(systemName: "book.fill")
                    Text("Learn")
                }
            PracticeView()
                .tabItem {
                    Image(systemName: "chart.bar.fill")
                    Text("Practice")
                }
            SettingsView()
                .tabItem {
                    Image(systemName: "gearshape.fill")
                    Text("Settings")
                }
        }

        .fullScreenCover(isPresented: $isQuizViewShowing) {
            if hasSelectedSet, let selectedSet = contentSelectedSet {
                DebugQuizView(
                    isPresented: $isQuizViewShowing,
//                    quizTitle: contentQuizTitle,
                    selectedSet: selectedSet
                )

            }
            else {
                Text("Selected set is nil") // show a message if selectedSet is nil
            }
        }

        }
}

Additionally if it helps, here is an example of the question that would be passed into ContentView from MenuView:

var questionsCore = [
    Question(text: "What is the capital of New Zealand?", options: ["What if one of the answer choices is a longer answer", "Christchurch", "Wellington", "Auckland"], correctAnswer: "Wellington", imageName: nil, originalOptions: ["What if one of the answer choices is a longer answer", "Christchurch", "Wellington", "Auckland"]),
    Question(text: "What is the highest mountain in New Zealand?", options: ["Mount Cook", "Mount Aspiring", "Mount Taranaki"], correctAnswer: "Mount Cook", imageName: UIImage(named: "cherry"), originalOptions: ["Mount Cook", "Mount Aspiring", "Mount Taranaki"]),
]

At first I thought it could have been an issue with the receiving view, but I made a new, empty one to check it and still receive the same issue there:

import SwiftUI

struct DebugQuizView: View {
    @Binding var isPresented: Bool
    @State var selectedSet: [Question]
    var body: some View {


        Text(selectedSet[1].text)
            .foregroundColor(Color.green)
    }
}

2

Answers


  1. You could try this approach, using a ObservableObject model class to hold
    your contentSelectedSet, as shown in the example code. Works for me.

    Why is using a simple @State var contentSelectedSet: [Question]? not working,
    I don’t know for sure, but @Paulw11 explanation seems to be correct.

    struct Question: Identifiable {
        let id = UUID()
        var text: String
        var options: [String]
        var correctAnswer: String
        var imageName: UIImage?
        var originalOptions: [String]
        
        static var questionsCore = [
            Question(text: "What is the capital of New Zealand?", options: ["What if one of the answer choices is a longer answer", "Christchurch", "Wellington", "Auckland"], correctAnswer: "Wellington", imageName: nil, originalOptions: ["What if one of the answer choices is a longer answer", "Christchurch", "Wellington", "Auckland"]),
            Question(text: "What is the highest mountain in New Zealand?", options: ["Mount Cook", "Mount Aspiring", "Mount Taranaki"], correctAnswer: "Mount Cook", imageName: UIImage(named: "cherry"), originalOptions: ["Mount Cook", "Mount Aspiring", "Mount Taranaki"]),
        ]
    }
    
    class Qmodel: ObservableObject {
        @Published var contentSelectedSet: [Question] = []  // <-- here
    }
    
    struct ContentView: View {
        @State private var isQuizViewShowing = false
        //    @State var contentQuizTitle = ""
        @StateObject var model = Qmodel()  // <-- here
        @State var hasSelectedSet = false
        
        var body: some View {
            TabView {
                Text("MenuView click on this")  // <-- for my testing
                    .onTapGesture {
                        model.contentSelectedSet = Question.questionsCore
                        hasSelectedSet = true
                        isQuizViewShowing = true
                    }
    //            MenuView(onQuizButtonTapped: { menuSelectedSet in
    //                contentSelectedSet = menuSelectedSet
    //                hasSelectedSet = true
    //                print("The content set is (String(describing: contentSelectedSet))")
    //                print("The selected set is (menuSelectedSet)")
    //                isQuizViewShowing = true})
                .tabItem {
                    Image(systemName: "book.fill")
                    Text("Learn")
                }
                Text("PracticeView")
                    .tabItem {
                        Image(systemName: "chart.bar.fill")
                        Text("Practice")
                    }
                Text("SettingsView")
                    .tabItem {
                        Image(systemName: "gearshape.fill")
                        Text("Settings")
                    }
            }
            .fullScreenCover(isPresented: $isQuizViewShowing) {
                if hasSelectedSet {  // <-- here
                    DebugQuizView(isPresented: $isQuizViewShowing,
                                  selectedSet: model.contentSelectedSet)
                }
                else {
                    Text("Selected set is nil") // show a message if selectedSet is nil
                }
            }
        }
    }
    
    struct DebugQuizView: View {
        @Binding var isPresented: Bool
        @State var selectedSet: [Question]
        
        var body: some View {
            Text(selectedSet[1].text)
                .foregroundColor(Color.green)
        }
    }
    
    Login or Signup to reply.
  2. It’s because you declared contentSelectedSet as @State but didn’t use it anywhere in body. SwiftUI’s dependency tracking feature only calls for body when states are set if they are ones that have been previously read in body. You can fix it by forcing a read in body like this:

    .fullScreenCover(isPresented: $isQuizViewShowing) { [contentSelectedSet] in
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search