포스트

Quizzler (4)

이어서… quizBrain.swift에서 function checkAnswer를 Bool type으로 하고 정답일때 true/ 틀렸을때 false return하게 하였다.

1
2
3
4
5
6
7
func checkAnswer(_ userAnswer: String) -> Bool {
        if userAnswer == quiz[questionNumber].answer {
            return true
        } else {
            return false
        }
    }

그리고 다시 viewController로 돌아가서 위와 같이 수정하였다.

이걸 다르게 또 보는사람이 쉽게 하기위해 표현이 가능할까?

이렇게 직관적으로 보이게도 할 수 있다.


Challenge! 그렇다면. 현재 아래 code는 quizBrain.swift에 관련 코드를 넣지 않고 입력한 상태이다.

아래코드가 작동하게 하려면 quizBrain에 어떤 code를 작성해야할지 한번 try해보자! before

1
2
3
4
5
@objc func updateUI() {
        questionLabel.text = quiz[questionNumber].text
        trueButton.backgroundColor = UIColor.clear
        falseButton.backgroundColor = UIColor.clear
        progresBar.progress = Float(questionNumber + 1 ) / Float(quiz.count)

after

1
2
3
4
5
6
@objc func updateUI() {
        questionLabel.text = quizBrain.getQuestionText()
        trueButton.backgroundColor = UIColor.clear
        falseButton.backgroundColor = UIColor.clear
        progresBar.progress = quizBrain.getProgress()
    }

quizBrain.swift 내가한것

1
2
3
4
5
6
7
8
9
10
11
12
func getQuestionText () -> String {
        var quiz : String = quiz[questionNumber].text
        
        return quiz
    }
    
    func getProgress() -> Float {
        
        var progress : Float = Float(questionNumber + 1) / Float(quiz.count)
        
        return progress
    }

강의에서의 코드

1
2
3
4
5
6
7
8
9
10
func getQuestionText () -> String {

        return quiz[questionNumber].text
    }
    
    func getProgress() -> Float {
        
        let progress = Float(questionNumber + 1) / Float(quiz.count)
        return progress
    }

뭐 또이또이하다 다만 차이라면 progress를 나는 var로 하였고 강의에서는 let으로 하였다.

그리고 questionNumber를 1씩 증가해주던 부분을 함수화 하여 quizBrain에 넣어주었다

1
2
3
4
5
6
7
func nextQuestion() {
        if questionNumber + 1 < quiz.count {
            questionNumber += 1
        } else {
            questionNumber = 0
        }
    }

그랬더니 immutable즉 변할 수 없는 값이라고 에러가 뜬다.

어떻게 해야할까?


여기서 immutable이란??

  • 불변성을 이야기한다.

우선 Struct = Blueprint 라고 볼 수 있다. 즉, 우리가 어떤 코드를 짤때에 있어 청사진을 그리는것이라고 이해하면 될 것 같다.

그리고 그 청사진을 그린것을 실체화하는걸 initializing이라고 보면 되겠다.

Blueprint -> actualization

var -> variable / mutable let -> immutable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct Town {
    let name : String
    var citizens : [String]
    var resources : [String : Int]
    
    init (name : String, citizens : [String], resources : [String : Int]){
        self.name = name
        self.citizens = citizens
        self.resources = resources
    }
    
    func fortify() {
        print("Defences increased!")
    }
    
    //func harvestRice()
}

var anotherTown = Town(name: "Nameless Island", citizens: ["Tom Hanks"], resources: ["Coconuts" : 100])
var myTown = Town(name: "Harold Island", citizens: ["Harold", "Timothy"], resources: ["Wool" : 75])

myTown.citizens.append("Keanu Reeves")

anotherTown.citizens.append("Wilson")

print(anotherTown.citizens)

이렇게 되어있는 코드에 sturcture 내부에 값을 한번 넣어보자!

1
2
3
4
func harvestRice() {
        resources["Rice"] = 100
    }

structure 내부에 function을 만들어, resources에 Rice라는 항목을 만들고 100이라는 값을 넣었다. 즉 [“Rice” : 100] 의 형태로 넣었다. 하지만 아래와 같이 에러가 발생한다.

우리가 위에 정의한 self는 기본적으로 immutable 즉, 변할 수 없는 값이기 때문이다.

  • let 과 함께 정의된다고 생각하면 된다.

Q: Self가 없는데 어디있는건가? A: 우리가 적은

1
resources["Rice"] = 100 

이것은 사실

1
self.resources["Rice"] = 100 

의 줄임 표현이다.


Q: 그렇다면 structure에서는 값을 변경할 수 없나? A: 아니다 아래와 같이 func 앞에 mutating을 추가해주면 된다.

1
2
3
4
mutating func harvestRice() {
--------
        resources["Rice"] = 100
    }

그럼 함수를 호출하고 출력을 해보자. 이렇게 추가된걸 볼 수 있다.

myTown.harvestRice()함수를 호출하지않으면, 아래와 같다.

함수 앞에 mutating을 붙이면 self는 var와 같은 역할을 수행하게 되고, 우리는 우리의 struct안에서 값을 자유롭게 바꿀 수 있다.

즉 struct는

  1. 값이 변할 수 없는 struct
  2. 값이 변하는 struct

이렇게 두개로 나눌 수 있다.


Q: 우리가 현재 myTown을 let아닌 var로 정의 했는데, let를 사용하면 harvestRice 함수를 호출을 할수 있을까?

1
2
3
var myTown = Town(name: "Harold Island", citizens: ["Harold", "Timothy"], resources: ["Wool" : 75])
// --- var를 let으로
let myTown = Town(name: "Harold Island", citizens: ["Harold", "Timothy"], resources: ["Wool" : 75])

A: Nope! 왜냐면 let은 바꿀수없는 상수이므로, 값을 변화시켜주는 harvestRice 함수를 호출 할 수없다. 그리고 let을 사용해서 매개변수를 정의를 하면, structure내의 모든 Properties들은 immutable이 되고, 또한 harvestRice 함수 앞에 적어둔 mutating또한 작동을 하지 않는다!!!


다시 내용으로 들어와서… immutable즉 변할 수 없는 값이라고 에러가 뜬다. 이부분에 대해 다시 이야기를 해보자. structure내부에서 questionNumber가 1씩 증가를 하거나 0으로 돌린다는건데 immutable이라 바꾸질 못한다. 그래서 func 앞에 mutating을 적어주었다.

1
2
3
4
5
6
7
mutating func nextQuestion() {
        if questionNumber + 1 < quiz.count {
            questionNumber += 1
        } else {
            questionNumber = 0
        }
    }

잘 작동한다.


challenge!

정답을 맞추면 score가 올라가게 해보자!


Let’s think!

  1. 로직은 어떻게 짜여야 할까?
    • 우선 생각해본 Logic flow는 정답일때 score가1씩 증가, 오답일때는 값이 그대로, 그리고 마지막문제에서 첫번째 문제로 돌아갈때 score 를 0으로 한다.
  2. 먼저 무엇을 해야할까?
    • QuizBrain.swift에 함수를 정의한다.
    • func getScore ~
  3. 함수를 정의를 했다. 그다음에는 어떻게 해야할까?
    • 우선 var score = 0 이라는 매개변수를 하나 만들어 주었다.
  4. 그 변수를 어디에 쓸건지?
    • 우선 로직 플로우 그대로 ```swift mutating func checkAnswer(_ userAnswer: String) -> Bool { if userAnswer == quiz[questionNumber].answer { score += 1 // updated! return true } else { return false } }

mutating func nextQuestion() { if questionNumber + 1 < quiz.count { questionNumber += 1 } else { questionNumber = 0 score = 0 // updated! } } ``` 처음에 내가 생각한게 맞나싶어서 했고 테스트만 안하고 확신이 없어서 완성한 코드를 더 꼬아버렸다. 그러다 도저히 안되어서 강의를 봤는데 내가생각하고 작성한게 맞았다. 확신을 좀 가지자…

무튼 완성!

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.