Варианты ответов в конце не отображаются в том же случайном порядке, что и на предыдущих экранах отдельно
Пытаюсь сделать приложение-тест с пятью вопросами и четырьмя вариантами ответов на каждый вопрос.
Все пять вопросов следуют один за другим, то есть каждый вопрос с четырьмя вариантами ответов отображается на отдельном экране. Затем на последнем экране все вопросы и ответы к ним отображаются на одном экране.
Цель состоит в том, чтобы, во-первых, отображать как вопросы, так и ответы в случайном порядке (когда они отображаются отдельно (1 вопрос и 4 ответа к нему)), так и, во-вторых, чтобы на последнем экране (где уже все пять вопросов и 4 варианта ответов к каждому из них) сохранялся тот же случайный порядок.
С вопросами сохраняется тот же случайный порядок, но ответы на финальном экране не сохраняют того же случайного порядка и отображаются в обычной первоначальной последовательности, в которой они хранятся в базе данных QuestionManager.
Как сделать так, чтобы варианты ответов отображались на финальном экране в той же последовательности как в отдельных вопросах, а не как в базе данных?
Ниже приведены примеры отдельного экрана, конечного экрана, базы данных и некоторые отдельные части моего кода.
Примеры 3-5 вопросов с вариантами ответов в произвольном порядке, и финальный экран, где все вопросы в том же произвольном порядке, что и в тесте, а ответы как базе данных QuestionManager.
Фрагмент из базы данных QuestionManager.
class QuestionManager {
enum LevelType: String {
case beginners = "Beginners"
case middle = "Middle"
case advanced = "Advanced"
}
// MARK: - Properties
private (set) var questions: [Question] = []
private (set) var answers: [Answer] = []
/*private (set)*/ var currentQuestion: Question?
private (set) var questionNumber: Int = 0
public var levelType: LevelType = .beginners
// MARK: - Constants
public let defaultQuestions: [LevelType: [Question]] = [
.beginners: [],
.middle: [],
.advanced: [
Question(text: "What is 2 / 2?", answers: [
Answer(text: "1", correct: true),
Answer(text: "2", correct: false),
Answer(text: "4", correct: false),
Answer(text: "7", correct: false)
], explanation: "The correct answer will be is as it is a Singular form."),
Question(text: "What is 10 / 2?", answers: [
Answer(text: "1", correct: false),
Answer(text: "4", correct: false),
Answer(text: "5", correct: true),
Answer(text: "12", correct: false)
], explanation: "The explanation will be given later."),
Question(text: "What is 27 / 3?", answers: [
Answer(text: "9", correct: true),
Answer(text: "10", correct: false),
Answer(text: "11", correct: false),
Answer(text: "12", correct: false)
], explanation: "The explanation will be given later."),
Question(text: "What is 32 / 4?", answers: [
Answer(text: "7", correct: false),
Answer(text: "8", correct: true),
Answer(text: "9", correct: false),
Answer(text: "10", correct: false)
], explanation: "The explanation will be given later."),
Question(text: "What is 100 / 2?", answers: [
Answer(text: "30", correct: false),
Answer(text: "40", correct: false),
Answer(text: "50", correct: true),
Answer(text: "100", correct: false)
], explanation: "The explanation will be given later.")
]
]
// MARK: - Public methods
public func shuffleQuestions() {
guard let questions = defaultQuestions[levelType]?.shuffled() else {
return
}
questionNumber = 1
self.questions = questions
}
public func upQuestionNumber() {
currentQuestion = self.questions[questionNumber - 1]
questionNumber += 1
}
}
GameViewController - контроллер вопросов по отдельности.
class GameViewController: UIViewController {
// MARK: - Create
static func create(with questionManager: QuestionManager) -> GameViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "game") as! GameViewController
vc.questionManager = questionManager
return vc
}
// MARK: - IBOutlets
@IBOutlet weak var questionCounterLabel: UILabel!
@IBOutlet weak var scoreLabel: UILabel!
@IBOutlet weak var progressView: UIProgressView!
@IBOutlet private var questionNumberLabel: UILabel!
@IBOutlet private var questionNameLabel: UILabel!
@IBOutlet weak var tableView: UITableView!
// MARK: - Properties
private var questionManager: QuestionManager!
private var score: Int = 0
let userDefaults = UserDefaults()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
questionManager.shuffleQuestions()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
showQuestion()
}
// MARK: - Configure UI
private func configureTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
}
// MARK: - QuizGame
private func showQuestion() {
questionManager.upQuestionNumber()
let stepProgress = Float(questionManager.questionNumber - 1) / Float(questionManager.questions.count)
progressView.progress = stepProgress
questionCounterLabel.text = "\(questionManager.questionNumber - 1)/\(questionManager.questions.count)"
scoreLabel.text = "Score: \(score)"
questionNameLabel.text = questionManager.currentQuestion?.text ?? ""
questionNumberLabel.text = "Question \(questionManager.questionNumber - 1)"
tableView.reloadData()
}
func pushToResultViewController() {
let vc = ResultViewController.create(with: questionManager)
self.navigationController?.pushViewController(vc, animated: true)
}
private func updateUI() {
progressView.progress = Float((questionManager.questionNumber - 1)/questionManager.questions.count)
scoreLabel.text = "Score: \(score)"
if questionManager.questionNumber > questionManager.questions.count {
let alert = UIAlertController(title: "Awesome",
message: "End of Quiz. Your result is: \(score) out of \(questionManager.questions.count)! Do you want to start over?",
preferredStyle: .alert)
let explanationAction = UIAlertAction(title: "Answer explanations",
style: .default,
handler: { action in
self.pushToResultViewController() }
)
alert.addAction(explanationAction)
present(alert, animated: true, completion: nil)
} else {
showQuestion()
}
}
}
// MARK: - UITableViewDelegate, UITableViewDataSource
extension GameViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
questionManager.currentQuestion?.answers.shuffle()
return questionManager.currentQuestion?.answers.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as? CustomTableViewCell else {
return UITableViewCell()
}
cell.textLabel?.text = questionManager.currentQuestion?.answers[indexPath.row].text
return cell
}
}
ResultViewController - контроллер последнего экрана, всех вопросов и ответов вместе.
class ResultViewController: UIViewController {
// MARK: - Properties
private var questionManager: QuestionManager!
private var questions: [Question] = []
private var answers: [Answer] = []
// MARK: - Create
static func create(with questionManager: QuestionManager) -> ResultViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "result") as! ResultViewController
vc.questionManager = questionManager
return vc
}
@IBOutlet weak var tableView: UITableView!
// MARK: - Private methods
private func configureTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "CustomFinalCell", bundle: nil), forCellReuseIdentifier: "customFinalCell")
}
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .cyan
navigationItem.setHidesBackButton(true, animated: true)
configureTableView()
}
}
// MARK: UITableViewDelegate, UITableViewDataSource
extension ResultViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionManager.questions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "customFinalCell", for: indexPath) as? CustomFinalCell else {
return UITableViewCell()
}
let question = questionManager.questions[indexPath.row]
answers = question.answers
cell.configure(with: question, with: answers)
return cell
}
}
CustomFinalCell
class CustomFinalCell: UITableViewCell {
private var questionManager: QuestionManager!
@IBOutlet weak var questionLabel: UILabel!
@IBOutlet weak var option1: UILabel!
@IBOutlet weak var option2: UILabel!
@IBOutlet weak var option3: UILabel!
@IBOutlet weak var option4: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
// MARK: - Public methods
public func configure(with question: Question, with answers: [Answer]) {
questionLabel.text = question.text
option1.text = question.answers[0].text
option2.text = question.answers[1].text
option3.text = question.answers[2].text
option4.text = question.answers[3].text
}
}
