You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中LazyVGrid切换题目后答案视图不更新问题求助

问题排查与解决

问题现象

手动修改questionNumber属性时,界面能正常显示对应题目和答案;但点击“Next Question”按钮切换题目时,题目文本更新正常,可TestAnswerTest视图未同步更新为新题目选项。不过在答案视图的点击手势中打印correctAnswers数组,显示的是当前题目的正确答案。

核心原因

  1. 子视图的@State误用:TestAnswerTest中的answer被声明为@State,@State会让视图持有该属性的内部状态,当父视图传递新的answer值时,子视图会优先保留自己持有的旧状态,而不是更新为新值。
  2. ForEach的id不唯一:LazyVGrid里的ForEach使用了id:\.self(即选项的索引),当不同题目选项数量相同时,SwiftUI会复用之前的TestAnswerTest实例,而不是创建新的实例,导致旧的answer值被保留。

解决方案

1. 修正子视图的状态声明

把TestAnswerTest中的@State var answer改为普通的let answer,因为answer是由父视图传递的外部数据,不需要子视图维护内部状态:

struct TestAnswerTest: View {
    let answer: String // 去掉@State修饰符
    @State private var selected = false
    var correctAnswers: [String]

    var body: some View {
        Text(answer)
            .font(.title)
            .bold()
            .frame(width: 165, height: 140)
            .contentShape(RoundedRectangle(cornerRadius: 25))
            .onTapGesture {
                self.selected.toggle()
            }
    }
}

2. 给ForEach设置唯一的id

为了让SwiftUI能准确识别每个选项的唯一性,避免视图复用,修改ForEach的标识逻辑:
可以给每个TestAnswerTest添加唯一id,用当前题目id加选项索引的组合:

LazyVGrid(columns: twoColumnGrid) {
    ForEach(0..<staffQuestions[questionNumber].options, id: \.self) { number in
        TestAnswerTest(
            answer: staffQuestions[questionNumber].answers[number],
            correctAnswers: staffQuestions[questionNumber].correctAnswers
        )
        .id("\(staffQuestions[questionNumber].id)-\(number)") // 添加唯一标识
    }
}

或者直接遍历answers数组,利用答案文本作为id(需确保题目内答案不重复):

LazyVGrid(columns: twoColumnGrid) {
    ForEach(staffQuestions[questionNumber].answers, id: \.self) { answer in
        TestAnswerTest(
            answer: answer,
            correctAnswers: staffQuestions[questionNumber].correctAnswers
        )
    }
}

额外优化建议

  • 提前过滤staff类题目,避免每次视图刷新都重复执行过滤逻辑:
struct StaffRecap2: View {
    @State private var questionNumber = 0
    private let twoColumnGrid = [GridItem(.flexible()), GridItem(.flexible())]
    let questions:[Question2] = Bundle.main.decode("questions.json")
    private let staffQuestions: [Question2]
    
    init() {
        staffQuestions = questions.filter { $0.category == "staff" }
    }
    
    // 剩余代码不变...
}
  • 修正按钮的禁用条件,避免数组越界崩溃:
Button {
    questionNumber += 1
    print(staffQuestions[questionNumber])
} label: {
    Text("Next Question")
}
.disabled(questionNumber >= staffQuestions.count - 1) // 修改为当前题目是最后一题时禁用

内容的提问来源于stack exchange,提问作者Chris Bromley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 18:40:45