At this point in the quiz, the app is supposed to calculate the final score. At the moment, it crashes after selecting an answer on the final question, with the title error appearing on the third line:
var score = 0
for question in QuestionController.questionsList {
score += question.selectedAnswerIndex!
Full code for that file below. It works fine in previous iterations of the app, but just started today. I know there's an issue with force-unwrapping optionals, but unclear why it only occurs in this instance:
import UIKit
class ViewController: UIViewController {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
self.title="Quiz"
self.view.backgroundColor=UIColor.white
setupViews()
}
@objc func btnGetStartedAction() {
let v=QuestionController()
self.navigationController?.pushViewController(v, animated: true)
}
func setupViews() {
self.view.addSubview(lblTitle)
lblTitle.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 150).isActive=true
lblTitle.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive=true
lblTitle.widthAnchor.constraint(equalToConstant: 250).isActive=true
lblTitle.heightAnchor.constraint(equalToConstant: 250).isActive=true
self.view.addSubview(btnGetStarted)
btnGetStarted.topAnchor.constraint(equalTo: lblTitle.bottomAnchor, constant: 20).isActive=true
btnGetStarted.heightAnchor.constraint(equalToConstant: 50).isActive=true
btnGetStarted.widthAnchor.constraint(equalToConstant: 150).isActive=true
btnGetStarted.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive=true
btnGetStarted.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0).isActive=true
}
let lblTitle: UILabel = {
let lbl=UILabel()
lbl.text="Have you ever wondered which character you are on Friends? Answer the question on this quiz."
lbl.textColor=UIColor.black
lbl.textAlignment = .center
lbl.font = UIFont.systemFont(ofSize: 30)
lbl.adjustsFontSizeToFitWidth = true
lbl.numberOfLines=0
lbl.sizeToFit()
lbl.translatesAutoresizingMaskIntoConstraints=false
return lbl
}()
let btnGetStarted: UIButton = {
let btn=UIButton()
btn.setTitle("Get Started", for: .normal)
btn.setTitleColor(UIColor.white, for: .normal)
btn.backgroundColor=UIColor.blue
btn.layer.cornerRadius=5
btn.layer.masksToBounds=true
btn.translatesAutoresizingMaskIntoConstraints=false
btn.addTarget(self, action: #selector(btnGetStartedAction), for: .touchUpInside)
return btn
}()
}
struct Question {
var questionString: String?
var answers: [String]?
var selectedAnswerIndex: Int?
}
class QuestionController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let cellId = "cellId"
let headerId = "headerId"
var tableView: UITableView?
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tableView?.frame = CGRect(x: 0, y: 64, width: self.view.frame.width, height: self.view.frame.height - 64)
}
static var questionsList: [Question] = [Question(questionString: "What is your favorite type of food?", answers: ["Sandwiches", "Pizza", "Seafood", "Unagi"], selectedAnswerIndex: nil), Question(questionString: "What do you do for a living?", answers: ["Paleontologist", "Actor", "Chef", "Waitress"], selectedAnswerIndex: nil), Question(questionString: "Were you on a break?", answers: ["Yes", "No"], selectedAnswerIndex: nil)]
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Question"
navigationController?.navigationBar.tintColor = UIColor.white
navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
tableView = UITableView()
tableView?.dataSource = self
tableView?.delegate = self
tableView?.estimatedRowHeight = 140
tableView?.sectionHeaderHeight = 100
self.tableView?.rowHeight = UITableViewAutomaticDimension
self.view.addSubview(self.tableView!)
tableView?.register(AnswerCell.self, forCellReuseIdentifier: cellId)
tableView?.register(QuestionHeader.self, forHeaderFooterViewReuseIdentifier: headerId)
tableView?.tableFooterView = UIView()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let index = navigationController?.viewControllers.index(of: self) {
let question = QuestionController.questionsList[index]
if let count = question.answers?.count {
return count
}
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath as IndexPath) as! AnswerCell
if let index = navigationController?.viewControllers.index(of: self) {
let question = QuestionController.questionsList[index]
cell.nameLabel.text = question.answers?[indexPath.row]
cell.nameLabel.numberOfLines = 0
cell.nameLabel.lineBreakMode = .byWordWrapping
}
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerId) as! QuestionHeader
if let index = navigationController?.viewControllers.index(of: self) {
let question = QuestionController.questionsList[index]
header.nameLabel.text = question.questionString
header.nameLabel.numberOfLines = 0
header.nameLabel.lineBreakMode = .byWordWrapping
}
return header
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let index = navigationController?.viewControllers.index(of: self) {
QuestionController.questionsList[index].selectedAnswerIndex = indexPath.item
if index < QuestionController.questionsList.count - 1 {
let questionController = QuestionController()
navigationController?.pushViewController(questionController, animated: true)
} else {
let controller = ResultsController()
navigationController?.pushViewController(controller, animated: true)
}
}
}
}
class ResultsController: UIViewController {
let resultsLabel: UILabel = {
let label = UILabel()
label.text = "Congratulations! You'd make a great Ross!"
label.contentMode = .scaleToFill
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 30)
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(done(sender:)))
navigationItem.title = "Results"
view.backgroundColor = UIColor.white
view.addSubview(resultsLabel)
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": resultsLabel]))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": resultsLabel]))
let names = ["Ross", "Joey", "Chandler", "Monica", "Rachel", "Phoebe"]
var score = 0
for question in QuestionController.questionsList {
score += question.selectedAnswerIndex!
}
let result = names[score % names.count]
resultsLabel.text = "Congratulations! \(result)."
}
@objc func done(sender: UIBarButtonItem) {
navigationController?.popToRootViewController(animated: true)
}
}