Swift测验应用:QuestionView无法切换至下一题的问题
问题分析与解决方案
问题根源
- 数据未被观察:
Quiz类是引用类型,但未遵循ObservableObject协议,修改progress和score时无法触发View刷新,导致界面感知不到进度变化。 - 题目参数未动态绑定:
QuestionView通过初始化参数接收固定的question,没有和quiz.progress关联,即使进度更新,题目也不会自动切换。 - 状态更新无响应:点击答案修改
quiz.progress后,因View未监听Quiz实例的变化,界面无法同步更新内容。
修复步骤
1. 修改Quiz模型,使其支持状态监听
让Quiz遵循ObservableObject,并将需要监听的属性标记为@Published:
import Combine class Quiz: Identifiable, ObservableObject { let id = UUID() let name: String let illustration: String let difficulty: Difficulty let questions: [Question] @Published var score: Int @Published var progress: Int init(name: String, illustration: String, difficulty: Difficulty, questions: [Question], score: Int, progress: Int) { self.name = name self.illustration = illustration self.difficulty = difficulty self.questions = questions self.score = score self.progress = progress } }
2. 重构QuestionView,动态绑定当前题目
移除固定的question参数,改为从quiz中动态获取当前题目,并通过@ObservedObject监听quiz的变化:
struct QuestionView: View { @ObservedObject var quiz: Quiz @State private var isFinished = false @State private var success = true // 动态计算当前题目 private var currentQuestion: Question { quiz.questions[quiz.progress] } var body: some View { VStack(spacing: 40) { VStack { Text(quiz.name) .font(.title3) .bold() HStack(spacing: 20) { ProgressBar(progress: 250 / CGFloat(quiz.questions.count) * CGFloat(quiz.progress)) Text("\(quiz.progress + 1)/\(quiz.questions.count)") .bold() } } Text(currentQuestion.questionText) .font(.title) .fontWeight(.semibold) .frame(width: 300) Spacer() LazyVGrid(columns: [GridItem(.adaptive(minimum: 160, maximum: 240))], spacing: 10) { ForEach(currentQuestion.answers) { answer in AnswerRow(answer: answer) .onTapGesture { if answer.isCorrect { if success { quiz.score += 1 } quiz.progress += 1 isFinished = true } else { success = false } } } } NavigationLink { // 检测是否完成所有题目,完成则跳转结果页 if quiz.progress < quiz.questions.count { QuestionView(quiz: quiz) } else { Text("测验完成!得分:\(quiz.score)") // 替换为你的结果页面,比如 ResultView(quiz: quiz) } } label: { PrimaryButton(text: "Continuer") } .disabled(!isFinished) // 启用禁用逻辑,防止未答题跳转 } .padding(.vertical, 60) .navigationBarHidden(true) } }
额外优化
- 简化了答案点击的逻辑判断,代码更简洁;
- 修正了
ForEach中变量名的语义错误(从index改为answer); - 增加测验完成的判断,避免超出题目数组索引;
- 启用
NavigationLink的禁用状态,提升交互合理性。
内容的提问来源于stack exchange,提问作者Julien01
相关产品推荐
相关产品推荐

