In the last lesson, we learn all about the Model-view-controller design pattern. 1
And in this lesson, we're going to apply the theory that we learned to our Quiz App. 2
First, we're going to separate out the part of our code that deals with the quiz data, namely this quiz 3
array and our Questions struct. 4
Go ahead and right-click on that Question.swift file and select New Group from Selection. 5
This is gonna create a folder that contains that Question.swift file and we're going to rename that 6
folder Model. 7
Next, we're gonna do the same thing for our Main.storyboard. 8
So we're going to create a new group and we're gonna call this one the View. 9
Finally, we're going to right-click on the ViewController.swift and create a new group called Controller. 10
So if your OCD like me, feel free to drag the folder around so that they are in the right order. 11
And now that we've set out our MVC structure, the next step is to actually do the work of converting 12
our code into the MVC design pattern. In order to do that, 13
we need to split up of ViewController.swift. The controller should really only be responsible for 14
telling the other components what to do and respond to changes in other components. 15
This means that the ViewController.swift should handle what to do with the user interaction from the 16
view and tell the view what it should display. 17
It should also fetch the relevant data from the model to send to the screen and tell the model to update 18
itself. 19
But at the moment, our view controller is handling all of the quiz data as well as all of the quiz logic. 20
So we first have to separate this part out. 21
Go ahead and right-click on the Model folder, create a new Swift file in there that we'll call the 22
QuizBrain. 23
This is going to be the brain of our quiz and it's going to handle all of the logic. In here, we're going 24
to create a new structure called QuizBrain. And the first thing that I'm going to add to this QuizBrain 25
is my quiz array here 26
that's currently living inside ViewController.swift. 27
So I'm going to cut it out and put it into my QuizBrain. And with a little bit of reformatting, 28
we should now have our quiz as a property of our QuizBrain. 29
Now, we don't need to initialize this quiz property because we've already given it the value that it 30
needs and it's never going to change because it's a constant. 31
And we're also not gonna be adding questions or removing questions in the middle of running our app. 32
Next, we're going to move the questionNumber variable over to the quiz brain as well because the QuizBrain 33
is now going to be the one that's tracking these sort of things to do with the quiz. 34
Now, at this point, if you take a look inside your ViewController, you'll notice that pretty much all hell 35
has broken loose out here, and there will be errors left, right, and center. 36
You might have doubts about whether if you should have started this endeavor at all. But fear not, 37
I'm here, and the result will be worth it, I promise. If we examine our answerPressed function, you can 38
see that it's actually currently fulfilling two roles. 39
One is the answer checking part and two is the quiz progression. 40
So going to the next question. 41
Now, let's create a new instance or new copy of our quizBrain at the top of our view controller. 42
So just below our IBOutlets, we're going to create a new variable called quizBrain. 43
And, of course, the copies of our struct need to be lowercase to begin with, and we're going to create that 44
from our quizBrain structure. 45
So QuizBrain in capitals and then a set of parentheses at the end. And you might need to just hit command 46
B every so often for it to recognize what you're talking about. 47
Now, we can use our QuizBrain inside our ViewController.swift. 48
So next, we're going to move our answer checking logic out of our ViewController.swift and make all 49
QuizBrain handle it instead. To do that, 50
we'll need a function inside our QuizBrain. 51
Now, whenever a function is associated with a structure or a class, basically, some sort of custom type 52
will then, usually, we call it a method. 53
But this is just something that's quite pedantic. 54
In reality, if you hear a functional method, they essentially refer to the same thing a package of instructions 55
wrapped inside a name. So inside the curly braces of my structure QuizBrain, I'm going to create my method 56
which is going to be called checkAnswer. And this method is gonna need an input in order to work. 57
So the input is gonna be the answer that the user chose 58
and this is gonna be a string. Next, we can go into our ViewController and delete this line of code. 59
Instead, we're going to move that functionality to our QuizBrain. 60
We're going to call quizBrain.checkAnswer. 61
And then, we should be able to add the parameter which is userAnswer. 62
And the argument that we're gonna pass in or the value is, of course, going to be this one. 63
It's gonna be userAnswer. 64
Now, if you think this is a little bit excessive in terms of the naming of our method, checkAnswer, userAnswer, 65
userAnswer, then one way of making this a little bit shorter is actually to add an external parameter 66
name. So remember that the parameter name refers to the name of the input that comes into the function. 67
So we can have an internal and an external parameter name in Swift. So for example, if I decided to call 68
the external parameter name answer, then I would be able to use answer here as the external parameter 69
name. 70
Meanwhile, inside the function, I can use the internal parameter name which is that userAnswer right 71
here. 72
Now, what we can also do is we could also simply say that there shouldn't be an external parameter name. 73
And to do that, we simply replace the excel parameter name, so the first part with an underscore. And now 74
inside our ViewController, we can simply write checkAnswer and pass in this as the argument. To remember, 75
the argument is the value that gets passed in as the input. The parameter is the name of the input 76
and we now have an external and an internal parameter name. We use the internal parameter name inside 77
the function. The external parameter name is used when we call the function. 78
And in this case, because we turned it into an underscore, it no longer needs an external parameter name. 79
And method now reads a lot better in English, 80
checkAnswer which answers the check, well, the user's answer, of course, which comes from here. 81
Now, at this point, we get an error that tells us that this userAnswer is actually an optional string. 82
But checkAnswer is, of course, expecting an actual string. 83
So in our case, because we only have two buttons that are linked to this IBAction and they both definitely 84
have a title, we can be fairly confident in force unwrapping this currentTitle. And that turns our 85
userAnswer into a actual string data type. 86
So now let's go back to our QuizBrain and check the userAnswer that was passed in against the actual 87
answer. 88
So let's add our "if" statement here, 89
check to see if the userAnswer is equal to the quiz at the current questionNumber.answer. 90
Well, then in that case, they got it right. 91
So user got it right. 92
But otherwise, then the user probably got it wrong. 93
So now, while we're in the process of implementing the MVC design pattern, we're coming up against a roadblock. 94
Our problem is that the answer checking happens in our quiz brain, but it's our vVewController that's 95
responsible for updating the UI, changing the sender's background color to green or to red. 96
How can we get the result of this check and some method out from the quizBrain and send it over here 97
into the ViewControlle? Well, if you can solve this problem, you might already know how to use Swift 98
functions that have outputs. 99
But if you don't know how to solve this, then head over to the next Swift Deep Dive where we talk about 100
the third type of functions, functions that can have outputs.