swiftswiftui

Cannot convert value of type 'Range<Int>' to expected argument type 'Binding<C>'


I'm making an app in Swift, where users have to answer a question. Multiple answers can be accepted, so I used a ForEach loop to check for all the answers. However, when I try to toggle a "correct" variable (so the "Correct!" message only shows once), I get an error (see title). The error is shown on line 77: ForEach(0..<data.answer.count, id: .self). Does anyone know how to fix this???

import SwiftUI

struct LocationView: View {
    @State private var submit: Bool = false
    @State private var guess = ""
    @State private var correct = false
    var data: Location
    
    var body: some View {
            Text(data.question)
                .padding()
            
            TextField("Answer", text: $guess)
                .padding()
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.green, lineWidth: 2)
                )
                .padding()
            
            Button(action: {
                submit.toggle()
            }) {
                Text("Submit")
                    .foregroundStyle(.blue)
                    .font(.headline)
            }
            
            if submit {
                ForEach(0 ..< data.answer.count, id: \.self) { answer in
                    if guess == data.answer[answer] {
                        correct.toggle()
                    }
                }

                if correct {
                    Text("Correct!")
                        .foregroundStyle(.green)
                        .font(.headline)
                }
            }
        }
    }
}

#Preview {
    let modelData = ModelData()
    LocationView(data: modelData.locations[0])
}

Solution

  • ForEach is for creating views from a collection. You have not provided any views inside foreach and it is not the right place just for a calculation.

    I have moved the calculation of verifying correct answer and changing submit state to button click action

    struct Location {
        let question: String
        let answer: [String]
    }
    
    struct LocationView: View {
        @State private var submitted: Bool = false
        @State private var guess = ""
        @State private var correct = false
        var data: Location
        
        var body: some View {
            question
            answer
            submitButton
            if submitted {
                message
            }
        }
        
        var question: some View {
            Text(data.question)
                .padding()
        }
        
        var answer: some View {
            TextField("Answer", text: $guess)
                .padding()
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.green, lineWidth: 2)
                )
                .padding()
                .disabled(!guess.isEmpty && submitted)
        }
        
        var submitButton: some View {
            Button(action: onSubmit) {
                Text("Submit")
                    .foregroundStyle(.blue)
                    .font(.headline)
            }
        }
        
        var message: some View {
            Group {
                if correct {
                    Text("Correct!")
                        .foregroundStyle(.green)
                } else {
                    Text("Wrong")
                        .foregroundStyle(.red)
                }
            }
            .font(.headline)
            .transition(.scale)
        }
        
        func onSubmit() {
            if !guess.isEmpty {
                withAnimation {
                    submitted = true
                    verifyAnswer()
                }
            }
        }
        
        func verifyAnswer() {
            correct = data.answer.contains(guess)
        }
    }
    
    #Preview {
        LocationView(data: Location(question: "guess number?", answer: ["one", "two", "three"]))
    }