Swift问答App点击选项无法切换下一题问题求助(附代码)
问题分析与解决方案
你的核心问题在于:切换题目索引后没有重新加载对应题目并触发UI更新,同时ViewController的更新逻辑缺失。以下是针对性的修复方案:
第一步:重构QuizManager,存储完整题目列表并支持切换通知
原代码仅在初始化时请求一次API并解析单题,无法利用返回的15道题进行切换。修改后将存储所有题目,切换索引后自动通知UI更新:
import Foundation protocol QuizManagerDelegate: AnyObject { func didUpdateQuiz(_ manager: QuizManager, quiz: QuizModel) } struct QuizManager { var index: Int = 0 private var quizResults: [Result]? private let maxQuestionCount = 15 // 与API请求的题目数量对应 weak var delegate: QuizManagerDelegate? mutating func nextQuestion() { index = (index + 1) % maxQuestionCount // 循环切换题目 loadCurrentQuestion() // 切换后加载当前题目并通知UI } func performRequest() { let urlString = "https://opentdb.com/api.php?amount=15&type=multiple" guard let url = URL(string: urlString) else { return } let session = URLSession(configuration: .default) let task = session.dataTask(with: url) { [weak self] data, _, error in guard let self = self else { return } if let error = error { print(error) return } guard let safeData = data else { return } if let welcome = self.parseFullQuizData(data: safeData) { self.quizResults = welcome.results self.loadCurrentQuestion() // 加载第一个题目 } } task.resume() } private func parseFullQuizData(data: Data) -> Welcome? { let decoder = JSONDecoder() do { return try decoder.decode(Welcome.self, from: data) } catch { print(error) return nil } } private func loadCurrentQuestion() { guard let results = quizResults, index < results.count else { return } let result = results[index] let correct = result.correct_answer ?? "error" let quest = result.question ?? "error" let incorrect = result.incorrect_answers ?? ["error"] let quiz = QuizModel(correctAnswer: correct, question: quest, falseAnswer: incorrect) delegate?.didUpdateQuiz(self, quiz: quiz) } }
修改说明:
- 新增
quizResults存储所有返回的题目,避免重复请求API nextQuestion()更新索引后自动调用loadCurrentQuestion(),触发UI更新- 协议改为
AnyObject,delegate用weak修饰避免循环引用 - 移除冗余的
nextQuestion(result: Bool)方法
第二步:完善ViewController的答题与更新逻辑
原代码的updateUI为空,且没有重置按钮状态。修改后实现完整的答题反馈与题目切换:
import UIKit class ViewController: UIViewController { @IBOutlet weak var ScoreLabel: UILabel! @IBOutlet weak var ChoiceButton4: UIButton! @IBOutlet weak var ChoiceButton3: UIButton! @IBOutlet weak var ChoiceButton2: UIButton! @IBOutlet weak var ChoiceButton1: UIButton! @IBOutlet weak var QuestionTextView: UITextView! var quizManager = QuizManager() var score = 0 var theQuiz: QuizModel? @IBAction func OptionsButtonPressed(_ sender: UIButton) { guard let thisQuiz = theQuiz, let btnTitle = sender.currentTitle else { return } // 显示答题结果颜色 if btnTitle == thisQuiz.correctAnswer { score += 1 ScoreLabel.text = "SCORE: \(score)" sender.setTitleColor(.systemGreen, for: .normal) } else { sender.setTitleColor(.systemRed, for: .normal) } // 延迟切换题目,让用户看到反馈 Timer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(switchToNextQuestion), userInfo: nil, repeats: false) } @objc private func switchToNextQuestion() { // 重置所有按钮颜色为默认 [ChoiceButton1, ChoiceButton2, ChoiceButton3, ChoiceButton4].forEach { $0?.setTitleColor(.label, for: .normal) } // 触发下一题加载 quizManager.nextQuestion() } override func viewDidLoad() { super.viewDidLoad() QuestionTextView.layer.cornerRadius = 15 quizManager.delegate = self quizManager.performRequest() ScoreLabel.text = "SCORE: \(score)" // 初始化分数显示 } } extension ViewController: QuizManagerDelegate { func didUpdateQuiz(_ manager: QuizManager, quiz: QuizModel) { DispatchQueue.main.async { self.theQuiz = quiz self.QuestionTextView.text = quiz.question // 整理并打乱选项 var allOptions = quiz.falseAnswer allOptions.append(quiz.correctAnswer) let shuffledOptions = allOptions.shuffled() // 设置按钮标题 ChoiceButton1.setTitle(shuffledOptions[0], for: .normal) ChoiceButton2.setTitle(shuffledOptions[1], for: .normal) ChoiceButton3.setTitle(shuffledOptions[2], for: .normal) ChoiceButton4.setTitle(shuffledOptions[3], for: .normal) } } }
修改说明:
- 将空的
updateUI替换为switchToNextQuestion,负责重置按钮状态并触发下一题 - 点击选项后先显示对错颜色,延迟0.35秒后切换题目,提升用户体验
- 简化选项整理逻辑,直接将正确答案加入错误选项数组后打乱
- 初始化时设置分数标签的初始值
第三步:其他小优化
- QuizData和QuizModel的代码可保持不变,若想减少
??处理,可给Codable结构体的属性添加默认值 - 建议对API返回的HTML转义字符(如
")进行解码,可在loadCurrentQuestion中添加quest = result.question?.replacingOccurrences(of: """, with: "\"") ?? "error"这类处理
内容的提问来源于stack exchange,提问作者Mert
相关产品推荐
相关产品推荐

