WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

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
    }
}

   

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.

   

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!

   

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

   

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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

Reply to this topic…

You need to create an account or log in to reply.

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.