UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Day 35- Edutainment app, app crashing.

Forums > 100 Days of SwiftUI

Whenever i try to select 5 (String) in the content view the app crashes. But if i select 1 then it works. I want to display a VStack of 5 questions when 5 is selected in the picker in content View. The code in Play strut(2nd view or the question display View)

import SwiftUI

struct Play: View {
    @Binding var questionLef: Questions
    @State var userAns = ""
   // @State var qRight = Questions(questionLeft: 0, questionRight: 1)
    @Binding var userQ: String
    var questionRight: Int {
        questionLef.changeNumber(value: 1)
    }
    @State var noOf = 1

    var body: some View {
        NavigationView {
        List {

                if (userQ == "1") {

                    HStack {
                        Spacer()
                        Text("\(questionLef.questionLeft + 1) * \(questionRight)")
                        Text(" = ")
                        TextField("Enter Answer", text: $userAns)
                            .frame(width: 200, height: 10)
                            .padding()
                            .border(/*@START_MENU_TOKEN@*/Color.black/*@END_MENU_TOKEN@*/, width: 1)
                            .padding()
                        Spacer()
                     }
                }
                else if (userQ == "5") {
                    ForEach(0 ..< 5) {col in
                        VStack {
                            Text("\(questionLef.questionLeft + 1) * \(questionRight)")

                        }
                    }
                }
                else {
                    HStack {
                        Spacer()
                        Text("\(questionLef.questionLeft + 1) * \(questionRight)")
                        Text(" = ")
                        TextField("Enter Answer", text: $userAns)
                            .frame(width: 200, height: 10)
                            .padding()
                            .border(/*@START_MENU_TOKEN@*/Color.black/*@END_MENU_TOKEN@*/, width: 1)
                            .padding()
                        Spacer()
                     }
                }
            }

        .navigationBarTitle("Questions")
        }
    }

}

struct Play_Previews: PreviewProvider {
    @State static var qLeft1 = Questions(questionLeft: 0, questionRight: 1)
    @State static var ques = "1"
    static var previews: some View {
        Play(questionLef: $qLeft1, userQ: $ques)
    }
}

2      

Crashes with what error?

2      

like when I try to open the navigation link button from the content view, it doesn't open and hangs and many times of strings(numbers too which is kinda greek to be) come in the log. and I have to rebuild it, even then it persist but then again if I do it by selecting userQ is 1 it shows me that single view as intended.

2      

That doesn't really help, unfortunately. Please copy and paste in whatever error you get in the debugger. Also, it would probably be useful to see your ContentView as well.

2      

Ok. this is my content View:

import SwiftUI
struct navModifier: ViewModifier {
    func body(content: Content)-> some View {
        content
            .foregroundColor(.white)
            .font(.custom("Helvetica",size: 40) .weight(.bold))
            .shadow(color: .green, radius: 3, x: 2, y: 1)
            .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 0))
    }
}

extension View {
    func navMod() -> some View {
        self.modifier(navModifier())
    }
}

struct ContentView: View {
    @State private var noQ = ["1", "5", "10", "15"]
    @State var userQues = "1"
    @State var qLeft = Questions(questionLeft: 0, questionRight: 1)

    var body: some View {
        NavigationView {
            ZStack {
                LinearGradient(gradient: Gradient(colors: [Color.yellow, Color.red]), startPoint: .topTrailing, endPoint: .bottomTrailing)
                    .edgesIgnoringSafeArea(.all)

                VStack {
                    Text("Settings")
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .padding(EdgeInsets(top: -20, leading: 20, bottom: 0, trailing: 0))
                        .font(.system(size: 30, weight: .semibold, design: .rounded))

                    Section(header: Text("Which table you wanna practice?")) {
                        Picker("Select Table", selection: $qLeft.questionLeft) {
                            ForEach(0 ..< 12) {
                                Text("\($0+1) Table")
                            }

                        }
                        .padding(EdgeInsets(top: -50, leading: 0, bottom: 0, trailing: 0))
                    }
                    .padding(EdgeInsets(top: 20, leading: 10, bottom: 0, trailing: 0))
                    .frame(maxWidth: .infinity, alignment: .leading)

                    Section(header: Text("How many questions do you want to answer ?")) {
                        Picker(selection: $userQues, label: Text("Select Questions")){
                            ForEach(noQ, id: \.self){

                                Text($0)
                            }
                        }
                        .padding(EdgeInsets(top: -60, leading: 0, bottom: 0, trailing: 0))
                    }
                    .padding(EdgeInsets(top: 20, leading: 10, bottom: 0, trailing: 0))
                    .frame(maxWidth: .infinity, alignment: .leading)

                    Section {

                        NavigationLink("Click to Begin",destination: Play(questionLef: $qLeft, userQ: $userQues))
                          .font(.system(size: 30, weight: .bold, design: .monospaced))
                            .foregroundColor(.white)
                    }

                    Spacer()
                }

            }.toolbar {
                ToolbarItemGroup(placement: .navigation){
                    Text("Tables App")
                        .navMod()
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    @State static var dummy: String = "1"
    static var previews: some View {
        ContentView()
    }
}

My Play view:

import SwiftUI

struct Play: View {
    @Binding var questionLef: Questions
    @State var userAns = ""
   // @State var qRight = Questions(questionLeft: 0, questionRight: 1)
    @Binding var userQ: String
    var questionRight: Int {
        questionLef.changeNumber(value: 1)
    }
    @State var noOf = 1
    var multiQ: String {
        let multiQuestion = "\(questionLef.questionLeft + 1) * \(questionRight)"
        return multiQuestion
    }

    var body: some View {
     NavigationView {
        List {

//                if (userQ == "1") {
//
//                    HStack {
//                        Spacer()
//                        Text("\(questionLef.questionLeft + 1) * \(questionRight)")
//                        Text(" = ")
//                        TextField("Enter Answer", text: $userAns)
//                            .frame(width: 200, height: 10)
//                            .padding()
//                            .border(/*@START_MENU_TOKEN@*/Color.black/*@END_MENU_TOKEN@*/, width: 1)
//                            .padding()
//                        Spacer()
//                     }
//                }
//                else if (userQ == "5") {
//                    ForEach(0 ..< 5, id: \.hashValue) { _ in
//
//                        Text("\(multiQ)")
//
//
//                        }
//
//                }
//                else {
//                    HStack {
//                        Spacer()
//                        Text("\(questionLef.questionLeft + 1) * \(questionRight)")
//                        Text(" = ")
//                        TextField("Enter Answer", text: $userAns)
//                            .frame(width: 200, height: 10)
//                            .padding()
//                            .border(/*@START_MENU_TOKEN@*/Color.black/*@END_MENU_TOKEN@*/, width: 1)
//                            .padding()
//                        Spacer()
//                     }
//                }
            MultipleLines(questionLef: $questionLef, userQ: $userQ)
            }
        .navigationBarTitle("Questions")
        }

    }

}

struct Play_Previews: PreviewProvider {
    @State static var qLeft1 = Questions(questionLeft: 0, questionRight: 1)
    @State static var ques = "1"
    static var previews: some View {
        Play(questionLef: $qLeft1, userQ: $ques)
    }
}

(I tried calling the view from a separte file but still didnt work.) The view that should display multiple lines.

import SwiftUI

struct MultipleLines: View {
    @Binding var questionLef: Questions
    @Binding var userQ: String
    var questionRight: Int {
        questionLef.changeNumber(value: 1)
    }
    var noQ: Int {
        Int(userQ) ?? 2
    }
    var body: some View {
        ForEach(0 ..< noQ) { _ in
            Text("\(questionLef.questionLeft + 1) * \(questionRight)")
        }
    }
}

struct MultipleLines_Previews: PreviewProvider {
    @State static var qLeft1 = Questions(questionLeft: 0, questionRight: 1)
    @State static var qL = "1"
    static var previews: some View {
        MultipleLines(questionLef: $qLeft1, userQ: $qL)
    }
}

Questions Struct:

import Foundation

struct Questions {
    var questionLeft: Int
    var questionRight: Int
    var actualAns: Int {
        (1 + questionLeft) * questionRight
    }
    init(questionLeft: Int, questionRight: Int) {
        self.questionLeft = 0
        self.questionRight = Int.random(in: 1...12)

    }

    mutating func changeNumber(value: Int) -> Int{
        questionRight = Int.random(in: 1...12)

        return questionRight
    }

}

2      

log: 2021-08-09 23:35:32.883998+0530 Tables[4731:88372] [Assert] UIScrollView does not support multiple observers implementing _observeScrollView:willEndDraggingWithVelocity:targetContentOffset:unclampedOriginalTarget:. Scroll view <_TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView: 0x7fedcd047800; baseClass = UITableView; frame = (0 0; 428 926); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x6000030c0d50>; layer = <CALayer: 0x600003e1ffc0>; contentOffset: {0, -239}; contentSize: {428, 220}; adjustedContentInset: {239, 0, 34, 0}; dataSource: <_TtGC7SwiftUIP13$7fff56921d2819ListCoreCoordinatorGVS_20SystemListDataSourceOs5Never_GOS_19SelectionManagerBoxS2_: 0x7fedcc617e60>>, new observer <_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS19SidebarStyleContext: 0x7fedcf83e400>, removing old observer <_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS19SidebarStyleContext: 0x7fedd004c800> 2021-08-09 23:35:32.884509+0530 Tables[4731:88372] [Assert] UIScrollView does not support multiple observers implementing _observeScrollView:willEndDraggingWithVelocity:targetContentOffset:unclampedOriginalTarget:. Scroll view <_TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView: 0x7fedcd047800; baseClass = UITableView; frame = (0 0; 428 926); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x6000030c0d50>; layer = <CALayer: 0x600003e1ffc0>; contentOffset: {0, -239}; contentSize: {428, 220}; adjustedContentInset: {239, 0, 34, 0}; dataSource: <_TtGC7SwiftUIP13$7fff56921d2819ListCoreCoordinatorGVS_20SystemListDataSourceOs5Never_GOS19SelectionManagerBoxS2: 0x7fedcc617e60>>, new observer <_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS19SidebarStyleContext: 0x7fedd004c800>, removing old observer <_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS19SidebarStyleContext: 0x7fedcf83e400>

If i removeve navigation View from play view this log doesnt come, but even then the app just hangs, it doesnt even move to the play view from content view.

2      

You definitely should remove the NavigationView from Play; it's already in a NavigationView because you are coming to it from ContentView. You don't need to nest them.

The hang you are experiencing is because you are mutating state during a view update. You should not do that.

The offending code is here:

var questionRight: Int {
    questionLef.changeNumber(value: 1)
}

Questions.changeNumber(value:) mutates the questionRight property. Trying to do that at the same time you are rendering the View, which you do here:

Text("\(questionLef.questionLeft + 1) * \(questionRight)")

is a bad idea. It apparently won't cause problems when it's just done once, which is why it works when you select "1", but it will if it happens multiple times, which is why it freaks out when you select "5" or "10" or "15".

You can see that it works correctly if, for instance, you use this instead:

var questionRight: Int {
    Int.random(in: 0...12)
}

This does not mutate your state, so it doesn't cause a problem when updating the view.

You need to rethink your model and how you are generating the questions to avoid this issue.

2      

Thanks a lot, the hanging problem was solved, so i did try to change my approach. To the code below:

struct MultipleLines: View {
    @Binding var questionLef: Int
    @Binding var userQ: String
    var questionRight: Int {
        Int.random(in: 0...12)
    }
    var questionLeft: Int {
       questionLef + 1
    }
    var actualAns: Int {
        calc(value1: questionLeft, value2: questionRight)
    }
    var noQ: Int {
        Int(userQ) ?? 2
    }
    var body: some View {
        ForEach(0 ..< noQ, id: \.self) { _ in
            Text("\(questionLeft) * \(questionRight)")
            Text("\(actualAns)")
        }
    }
    func changingNum(vaue: Int) -> Int {
        return Int.random(in: 0...12)
    }
    func calc(value1: Int, value2: Int) -> Int {
        let ans = value1 * value2
        return ans
    }
}

I am not getting the actual answer according to what the question right is displayed. I think it is becasue its taking two instances. what to do if i want to get the actual Ans accordingly ?

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.