I have an app that consist of 3 layer of views. The func of the app is to let student to look at the question, choice the answer, and have the app to check if the answer is correct (this is the func I am struggling right now).
ContentView - generate a random id (ranId) and pass it to the ChoiceView. ChoiceView is a component in this view.
ChoiceView* - to combine the different ChoiceRowView after a ForEach loop and pass the String as a label to Choice RowView from the ranId
ChoiceRowView* - control how each row look like in the ChoiceView and to check the answer for each answer.
I tried to use the Protocol-delegate method, but I can't figure out how to use it with the ForEach loop. I understand there are other ways to do it, like didSet, but I would rather stay with the protocol-delegate method for now. Thanks!!
Code in ChoiceView.swift
import SwiftUI
struct ChoiceView: View {
var ranId_CV : Int // random id pass from ContentView
var delegate : ChoiceRowView?
func test_CV() {
delegate?.checkAnswer()
}
var body: some View {
ScrollView {
HStack{
VStack(alignment: .leading){
ForEach (qandaData[ranId_CV].choices.components(separatedBy: "\n"), id: \.self){ item in
ChoiceRowView(label: String(item), answer: String(qandaData[self.ranId_CV].answer))
}
}
.fixedSize(horizontal: false, vertical: true)
Spacer()
}
.padding([.top, .leading, .bottom, .trailing])
Button(action: test_CV) { Text("Test_CV") } // this should work, but it doesn't
}
}
}
struct ChoiceView_Previews: PreviewProvider {
static var previews: some View {
ChoiceView(ranId_CV: 125)
}
}
Code in ChoiceRowView.swift
import SwiftUI
protocol checkAnswerProtocol {
func checkAnswer()
}
struct ChoiceRowView: View, checkAnswerProtocol {
var label: String
var answer: String
@State var isChecked : Bool = false
@State var fgColor : String = "black"
func buttonPress() {
isChecked = !isChecked
if isChecked == false {
fgColor = "black"
} else {
fgColor = "blue"
}
// selectedAnswer = selectedAnswer.filter { $0 != item_BP.prefix(1) }
}
func checkAnswer() {
print("executed checkAnswer")
switch (isChecked, answer.contains(String(label.prefix(1)))) {
//selected = isChecked = true, qandaData.answer contain prefix(1) => change to green
case (true, true) : fgColor = "green"
//selected = isChecked = true, incorrect => change to red
case (true, false) : fgColor = "red"
//unselected = isChecked = false, correct => change to red
case (false, true) : fgColor = "red"
//unselected = isChecked = false, incorrect => remain unchange
default: print("do nothing")
}
}
var body: some View {
Button(action: buttonPress) {
HStack{
Image(systemName: isChecked ? "checkmark.square": "square")
Text(label)
}
.foregroundColor(Color(String(fgColor)))
Button(action: checkAnswer) { Text("Test") }
}
}
}
struct ChoiceRow_Previews: PreviewProvider {
static var previews: some View {
ChoiceRowView(label: "label", answer: "AB")
}
}
Sample of qandaData[ranId_CV]
"id": 1,
"question": "Which ones are odd number?",
"choices": "A. 1\nB. 2\nC. 3\nD. 4",
"answer": "AC"

Questionstruct that can tell you whether an answer is correct or not. That said, I can't see anywhere where you are setting the delegate.nilnilobject? I am very new to app development, this is my first app, please excuse me...delegateproperty and tries to invoke a method in that property, but you never assign anything to that property. You need to assign some object that conforms to the protocol to that property; an instance ofChoiceRowViewbased on your code, but as I said your views shouldn't be delegates in SwiftUI. Delegation isn't the right pattern to use here