IBAction
함수에서 실행문 코드를 변경해준다.
// 사용자가 입력한 답 채점
if userAnswer == actualAnswer{
sender.backgroundColor=UIColor.green
} else {
sender.backgroundColor=UIColor.red
}
채점결과를 색상으로 알려주지만 문제는 다음 문제에서도 이전 버튼 채점결과 색상이 그대로 남아있다.
이는 updateUI()
함수에서 수정할 수 있다.
func updateUI() { // 문제번호를 업데이트 하는 함수
questionLabel.text = quiz[questionNumber].text
trueButton.backgroundColor = UIColor.clear
falseButton.backgroundColor = UIColor.clear
}
위와 같이 수정하고 실행시키면, 아예 채점 결과 색상이 변하지 않는 문제를 확인할 수 있다.
@IBAction func answerButtonPressed(_ sender: UIButton) {
let userAnswer = sender.currentTitle // 사용자의 답에 currentTitle의 sender 값을 넣는다 (True, False)
let actualAnswer = quiz[questionNumber].answer
if userAnswer == actualAnswer{
sender.backgroundColor=UIColor.green
} else {
sender.backgroundColor=UIColor.red
}
if questionNumber + 1 < quiz.count {
questionNumber += 1
} else {
questionNumber = 0
}
updateUI()
}
색상이 변한 뒤 바로 updateUI()
함수가 나오면서 바로 clear 시키기 때문에 사용자에게는 보이지 않는 것. 채점 결과를 보여주는 변경된 버튼에 대해 일정 시간 지연시켜주는 timer를 통해서 이를 해결해보자.
timer = Timer.scheduledTimer(timeInterval: 2.0, target:self, selector: #selector(updateUI), userInfo: nil, repeats: false)
그러나 여전히 해결되지 않았다.
repeats
를 false
로 설정했기 때문에 반복되지 않고 꺼지는데, 이후에 updateUI()
를 다시 호출함으로써 clear 해버렸기 때문. 다음과 같이 코드를 수정하고 정상적으로 작동하게 되었다.
@IBAction func answerButtonPressed(_ sender: UIButton) {
let userAnswer = sender.currentTitle // 사용자의 답에 currentTitle의 sender 값을 넣는다 (True, False)
let actualAnswer = quiz[questionNumber].answer
// 사용자가 입력한 답 채점
if userAnswer == actualAnswer{
sender.backgroundColor = UIColor.green
} else {
sender.backgroundColor = UIColor.red
}
// 문제번호를 하나씩 늘려간다
if questionNumber + 1 < quiz.count {
questionNumber += 1
} else {
questionNumber = 0
}
Timer.scheduledTimer(timeInterval: 0.2, target:self, selector: #selector(updateUI), userInfo: nil, repeats: false)
}
progressBar.progress = Float(questionNumber + 1) / Float(quiz.count)
questionNumber
에 더하기 1을 해준 이유는 progressBar의 진행을 끝까지 채워주기 위해 해 준 것 (이 역시 EggTimer와 동일하다) 퀴즈앱에서 문제가 되는 부분들이 코드의 앞부분을 차지하면서 가독성이 많이 떨어지게 되었다. 만약 문제가 방대해 진다면 점점 컨트롤하기가 어려워질 것이다. 이를 구조화하기 위한 MVC 패턴에 대해 알아보자.
MVC패턴은 프로그램을 특성에 따라 서로 영향을 미치지 않을 수 있는 범위로 분리해놓았기 때문에 데이터 관리 부분을 수정해도 비즈니스 로직이나 화면 표현 코드에 영향 미치지 않으며 화면을 표현하는 코드 수정하더라도 비즈니스 로직이나 데이터 관리 부분에 영향 미치지 않을 수 있다. 코드 재사용에 매우 유용하다.
이제 이를 퀴즈앱에 적용해보자.
import Foundation
struct QuizBrain {
let quiz = [
Question(q: "A slug's blood is green.", a: "True"),
Question(q: "Approximately one quarter of human bones are in the feet.", a: "True"),
// ~~ blah blah ~~ many questions in here
]
var questionNumber = 0
}
QuizBrain
(Model)
import Foundation
struct QuizBrain {
let quiz = [
Question(q: "A slug's blood is green.", a: "True"),
Question(q: "Approximately one quarter of human bones are in the feet.", a: "True"),
// blah blah ~~ Questions in here
]
var questionNumber = 0 // 문제번호 초기화
// 모든 기능을 함수로 구현하였다.
func checkAnswer(_ userAnswer: String) -> Bool {
// 사용자가 정답을 입력하면 채점하는 함수
if userAnswer == quiz[questionNumber].answer {
return true
} else {
return false
}
}
func getQuestionText() ->String {
// 문제를 출력하는 함수
return quiz[questionNumber].text
}
func getProgress() -> Float {
// Progress Bar 설정 함수
let progress = Float(questionNumber) / Float(quiz.count)
return progress
}
mutating func nextQuestion(){
// 다음 문제를 출력하는 함수
if questionNumber + 1 < quiz.count {
questionNumber += 1
} else {
questionNumber = 0
}
}
}
ViewController
(View)
// QuizBrain에서 정의했던 함수들을 호출해서 사용하고 있다
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var questionLabel: UILabel!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var trueButton: UIButton!
@IBOutlet weak var falseButton: UIButton!
var quizBrain = QuizBrain()
override func viewDidLoad() {
super.viewDidLoad()
updateUI() // updateUI()함수 호출
}
@IBAction func answerButtonPressed(_ sender: UIButton) {
let userAnswer = sender.currentTitle! // 사용자의 답에 currentTitle의 sender 값을 넣는다 (True, False)
let userGotItRight = quizBrain.checkAnswer(userAnswer) // Model - QuizBrain에서 underscore로 처리해주었으므로
// 사용자가 입력한 답 채점
if userGotItRight {
sender.backgroundColor = UIColor.green
} else {
sender.backgroundColor = UIColor.red
}
quizBrain.nextQuestion()
Timer.scheduledTimer(timeInterval: 0.2, target:self, selector: #selector(updateUI), userInfo: nil, repeats: false)
}
@objc func updateUI() { // 문제번호를 업데이트 하는 함수
questionLabel.text = quizBrain.getQuestionText()
// 문제를 출력할거니까! questionNumber array의 첫번재 요소를 문제로 쓸 것
progressBar.progress = quizBrain.getProgress()
trueButton.backgroundColor = UIColor.clear
falseButton.backgroundColor = UIColor.clear
}
}
var score = 0 // 점수 초기화
mutating func checkAnswer(_ userAnswer: String) -> Bool {
// 사용자가 정답을 입력하면 채점하는 함수
if userAnswer == quiz[questionNumber].answer {
score += 1
return true
} else {
return false
}
}
mutating func getScore() -> Int {
return score
}
@objc func updateUI() { // 문제번호를 업데이트 하는 함수
questionLabel.text = quizBrain.getQuestionText()
progressBar.progress = quizBrain.getProgress()
scoreLabel.text = "Score: \(quizBrain.getScore())"
// scoreLabel의 property 인 text 값에다가 getScore() 함수를 불러온다
trueButton.backgroundColor = UIColor.clear
falseButton.backgroundColor = UIColor.clear
}