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

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转义字符(如&quot;)进行解码,可在loadCurrentQuestion中添加quest = result.question?.replacingOccurrences(of: "&quot;", with: "\"") ?? "error"这类处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 00:35:21