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

Day 35 Challenge

Forums > 100 Days of SwiftUI

I'm struggling with a portion of the Multiplication game and think I may have a basic misunderstanding of what is going on. My approach has been to create a struct for a Question (multiplicands and answers), then an array of random questions corresponding to the parameters. For each round, then, I would pop the last Question off the array and compare the user input to the answer and update score. Seemed straightforward.

Problem I'm having is that whenever I try to initialize the first question as var q : Question = questions.popLast() in some form, I get into a spot where Swift tells me that I'm trying to use a property initializer before self is available. I've tried changing it to be in a function, in a closure, using lazy or even an init function all to no avail. Help!

import SwiftUI

struct Question {
    var num1 : Int
    var num2 : Int
    var answer : Int
}

struct ContentView: View {

    @State private var maxNumber = 20
    @State private var numberOfQuestions = 10
    @State public var questions = [Question]()
    @State public var answer = ""
    @State public var showingSheet = true
    @State public var playerScore = 0
    @State public var q : Question = nextQuestion() // getting error here: swiftui property initializers run before 'self' is available

    var body: some View {
        NavigationView {
            ZStack {
                LinearGradient(gradient: Gradient(colors: [.blue, .black]), startPoint: .top, endPoint: .bottom)
                    .ignoresSafeArea()
                VStack {
                    Image(systemName: "square")
                        .foregroundColor(.white)
                        .shadow(radius: 2.0)
                    Text("What is")
                        .foregroundColor(.white)
                        .font(.largeTitle)
                        .shadow(radius: 2.0)
                    Text("\(q.num1) X \(q.num2)?")
                    // Text("3 X 5?")
                        .foregroundColor(.white)
                        .font(.largeTitle)
                        .shadow(radius: 2.0)
                    TextField("Answer?", text: $answer)
                        .foregroundColor(.white)
                        .buttonStyle(.bordered)
                        .padding()
                        .keyboardType(.numberPad)

                }
            }

            .sheet(isPresented: $showingSheet) {
                Form {
                    Text("Start a new game")
                        .font(.largeTitle)
                    Stepper("Highest Multiple Number:\n\(maxNumber)", value: $maxNumber)
                    Stepper("Number of Questions:\n\(numberOfQuestions)", value: $numberOfQuestions)
                    Button("Start Game") {
                        showingSheet.toggle()
                        generateQuestions(max: maxNumber, number: numberOfQuestions)
                        // q = nextQuestion()
                    }
                }
            }
        }
        .toolbar {
            ToolbarItemGroup(placement: .bottomBar) {
                Text("Score: \(playerScore)")
                Spacer()
                Button {
                    showingSheet.toggle()
                } label: {
                    Image(systemName: "gear")
                }
            }
        }
    }

    func generateQuestions(max : Int, number : Int) {
        questions.removeAll()
        for _ in 1...number {
            var first = Int.random(in: 2...max)
            var second = Int.random(in: 2...max)
            var product = first * second
            var newQuestion = Question(num1: first, num2: second, answer: product)
            print(first, second, product)
            questions.append(newQuestion)
        }
         // var q = questions.popLast()!
    }
    mutating func nextQuestion() -> Question {
        let question = questions.popLast()
        return (question)!
    }

    func isCorrect(q: Question, a: Int) -> Bool {
        return a == q.answer
    }
}

1      

You're almost there.

  1. Assign a default Question to q, maybe Question(num1: 0, num2: 0, answer: 0)
  2. Uncomment the q = nextQuestion() line
  3. nextQuestion() doesn't mutate anything in the struct, so don't mark it as mutating

Note: Instead of assigning a default Question to q, you could make q an optional. That would require a few more tweaks elsewhere in your code. Either way would work in the end, though.

And another note: The way you are generating the questions array includes the possibility of duplicate questions. If you don't want duplicate questions, you will need to adjust your approach.

1      

Thanks so much for your help, that did it! Your point about dupe questions is a good one. My thought was to create the entire pool of possible questions (iteration) and then randomly pick n from the pool. On my to-do list!

1      

Thanks for this thread. Very helpful when I got stuck.

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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.