[Quiz 앱 2] MVC Design Pattern
채점 결과 알려주기
색상으로 알려주기
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)
그러나 여전히 해결되지 않았다.
- 원인 1 : EggTimer에서 썼던 함수를 가져오면서 Timer 함수를 timer 라는 변수에 넣어주는 코드를 썼기 때문. 수정 이후에도 문제 해결 되지않았다.
- 원인 2 : Timer()함수 내부에
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)
}
Progress Bar
progressBar.progress = Float(questionNumber + 1) / Float(quiz.count)
- progressBar의 property인 progress를 설정해준다.
- quiz의 갯수를 세어서 이를 questionNumber로 나누어주는데 각각 Float로 형변환 해준 이유는 EggTimer 에서와 동일하다. (Float로 형변환을 먼저 하여야 정확한 값을 얻을 수 있기 때문)
questionNumber
에 더하기 1을 해준 이유는 progressBar의 진행을 끝까지 채워주기 위해 해 준 것 (이 역시 EggTimer와 동일하다)
MVC Pattern
퀴즈앱에서 문제가 되는 부분들이 코드의 앞부분을 차지하면서 가독성이 많이 떨어지게 되었다. 만약 문제가 방대해 진다면 점점 컨트롤하기가 어려워질 것이다. 이를 구조화하기 위한 MVC 패턴에 대해 알아보자.
- MVC Design Pattern
MVC 패턴은 여러 디자인 패턴 중 하나로, Model-View-Controller 세 개의 핵심구조를 이용해 애플리케이션을 설계하는 것이다.- Model : 데이터를 담당
- View : 데이터에 대한 화면 표현을 담당
- Controller : 모델과 뷰 사이에 위치해 데이터를 가공해 뷰로 전달하며, 뷰에서 발생하는 이벤트를 입력받아 처리하는 역할을 한다.
MVC패턴은 프로그램을 특성에 따라 서로 영향을 미치지 않을 수 있는 범위로 분리해놓았기 때문에 데이터 관리 부분을 수정해도 비즈니스 로직이나 화면 표현 코드에 영향 미치지 않으며 화면을 표현하는 코드 수정하더라도 비즈니스 로직이나 데이터 관리 부분에 영향 미치지 않을 수 있다. 코드 재사용에 매우 유용하다.
이제 이를 퀴즈앱에 적용해보자.
- 질문들의 모음은 (데이터들) Model로, Main.storyboard는 View로, ViewController는 Controller로 그룹화해준다.
- 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 ~~ many questions in here
]
var questionNumber = 0
}
- 다시 ViewController로 가보면 코드가 오류 투성이다. 이를 해결하기 위해 다음과 같이 코드를 수정하였다.
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
}
}
score 출력하기
- score Label을 만들고 IBOutlet 연결해준다.
- Model에서 채점 결과 맞는 경우 score값을 1씩 증가시킨다.
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
}
- 이 함수를 View에서 다음과 같이 받아온다.
@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
}
결과물
Author And Source
이 문제에 관하여([Quiz 앱 2] MVC Design Pattern), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rubyy/Quiz-앱-2-MVC-Design-Pattern저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)