Now, at this stage, your developer instincts should be tingling because we've created this entire app 1
with just a single file, ViewController.swift. And all of our functionality, all of the components are 2
living and sharing this tiny space of one file. 3
So given that in the advanced section of our Swift Tutorials, we're talking a lot about architecture 4
and design patterns, 5
so that our app is well organized and extensible, then we should really be thinking about applying MVC 6
or the model-view-controller pattern to our app. 7
So let's go ahead and do that. As a challenge, 8
can you create a new Swift File to create a separate class? And inside that class, we're going to put 9
in all of the calculation logic that's currently inside the ViewController. 10
So create a new class called Calculator Logic and put that into a new Swift File. 11
All right. 12
So this is pretty easy. 13
We're just going to select the folder and I'm going to hit command Nto bring up the shortcut for 14
creating a new file, and we're inside iOS Swift File. 15
So if you're ever confused about whether if you should create a new Cocoa Touch Class or if you want 16
to use a new Swift File, then remember that whenever you want to subclass something, such as a UIViewController, 17
a UITableViewController, a UIView, whatever it may be, then you're going to choose this one. 18
But when you create your own custom classes, then you're going to be choosing a boggled standard Swift File. 19
So let's hit next and let's call this file Calculator Logic. 20
And I'm going to move it right up close to my ViewController. 21
Now, at this stage, I'm going to separate it out into MVC. 22
So I'm going to right click on my CalculatorLogic file and I'm going to select New Group from selection, 23
so that I can put it inside my Model file, and then I'm going to do the same with my ViewController, 24
and that is going to be my Controller. And my Main.storyboard is going to be placed inside a View 25
folder. 26
So, now I have MVC and we're going to go into our Model and create a brand-new Swift class. 27
Now, the class name is going to be the same as the name of the file, which is good programming practice, 28
so that way when you look inside your file inspector over here, you can see at a glance all of the classes 29
that you have included in your project. 30
Now, my class is not going to inherit from any other superclass. So I'm just going to delete that placeholder. 31
And there we have it. 32
We have a brand-new class and we've separated all of our files into the MVC structure. 33
Now, the next part you'll notice is that here I'm importing Foundation which is a library of code that 34
includes all of the Swift code. 35
But if you look inside View Controller.swift, 36
you can see I'm importing UIKit. 37
Now, this includes everything that's inside Foundation, but it also has a whole bunch of UI related things, 38
such as UIViewController or a UILabel. 39
Basically, every class that has UI to begin with it is inside UIKit and you'll need to import UIKit 40
if you need to work with the user interface. 41
Now, in our CalculatorLogic, we don't need to do any of that. 42
So Foundation is perfectly fine. 43
Now, the next step is we want to move all of this calculation-related code into our brand-new 44
CalculatorLogic model. So see if you can complete this as a challenge, 45
see if you can move all of this into our CalculatorLogic and make sure that it still works 46
when you test the app. 47
All right. 48
So first things first, let's create a new function over here and let's call it calculate. Now, this calculate 49
function is going to take a single parameter which is called symbol, and it's going to be in the form of 50
a String. 51
Now, my calculate function is where I'm going to transplant all of this code over. 52
Now, you might think that you can just transplant everything including the "if let," but let me show you 53
what happens when we do that. 54
So if you ever want to refresh the app when your errors are not occurring, then just try and hit command B 55
and all the errors that are not meant to be there should be cleared, and the errors that are meant 56
to be there will show up. 57
So the first issue we have is use of unresolved identifiers slender. 58
And the problem is that that sender variable comes from this input here and it refers to the button that 59
triggered the IBAction. 60
So there is no such thing as sender over here. 61
So we have to make sure that we actually keep the "if let" over here inside our ViewController right 62
here. 63
So we can't actually transplant that part over because we don't have an IBAction with a button that's 64
going to act as the sender giving us the information about which button got tapped by the user. 65
However, if the calc button gets pressed, then we can check to see if sender.currentTitle is not nil, 66
and in that case, we'll bind it to something called calcMethod, and that is what we're going to pass 67
over to our CalculatorLogic. 68
So we have one extra bracket down here 69
because, previously, I deleted the "if let," 70
so make sure that we delete the bottom one as well. 71
Now, the next step is you can see that there's quite a few of "Use of unresolved identifiers." 72
And the thing that it doesn't know about is this thing called calcMethod. 73
Well, inside this function, we've decided to call the calcMethod a symbol. 74
So we need to replace all the instances where we've got calcMethod with symbol. 75
So you can go ahead and hit command F to find this thing called calcMethod in this file. 76
And if you click the dropdown, we can give it some replacement text, and we'll instead replace it with 77
symbol. 78
So let's replace that one, that one, and that one. 79
And now, those errors will go away because we're going to pass in the calcMethod as a symbol parameter, 80
and then we're going to check against that symbol inside this function. 81
The next one that it doesn't recognize is this thing called displayValue. 82
And if you remember, displayValue was our computed property up here, 83
and we figured out what the value of it is by looking into the displayLabel and getting the current 84
value. 85
Now, we don't have a display label over here and we don't have a display value either. 86
So we're going to have to create a new property inside this class and we'll just call it something simple 87
like number. 88
This is going to be of type Double and it's not going to have a value until we pass it over from the 89
ViewController. So we can either set this to a optional Double, or as you can see, if I want to leave 90
it as this, then it tells me that I have to initialize number when we create a new object from this class. 91
So that means I have to add some init code. So I could say something like init(number) which is going 92
to be a Double. And inside the init, I'm going to tap into self.number. 93
Now, whenever you're using properties or methods associated with the current class, 94
so in this case, CalculatorLogic, you can refer to the properties and methods with this keyword "self" 95
in front of it. 96
This means that we're looking inside the current class for something called number. 97
And when you start typing number, you can see that in the left-hand side, we've got this "V" here, 98
and this is telling us that this is a global variable. 99
So if I hit enter, then I'm saying self.number, namely, this property should equal number, and that 100
number is going to be passed in when CalculatorLogic gets initialized. 101
And when I select it, you can see it's got a "L" symbol next to it which means that is a local variable 102
which refers to this number. 103
So while I can easily just write 104
number = number, and it sort of makes sense, right? 105
We're saying this left-hand side is this one. We're trying to set it to equal this one which is going 106
to be the number that gets passed in through the init. 107
Now, unfortunately, that does not make very much sense to either human or the computer, because even though 108
they're named exactly the same, it's very, very confusing which one you're trying to set and which one 109
you're trying to get. Now, one way of solving this is to simply make your global and local variables have 110
different names. Because then you could say number = n and that's a lot clearer what it is that 111
you're trying to change and what it is you're trying to grab the value for. 112
Now, another way of addressing this is simply by adding the keyword "self" in front of the properties. 113
So in this case, this is the property and we're saying "self," namely, in this current class, find a property 114
called number, and there it is, and set it to equal the local version of number. 115
So that is what the keyword "self" is for. 116
It always refers to the current class, whatever it is that we're within. 117
So, now we have a way of passing in a number to calculate. 118
We have a function that performs the calculation and all we need now is just a way of giving the result 119
back, 120
and the result is probably going to be in the format of a Double. 121
So we can fix these three lines of code that currently have errors to, instead, return the number multiplied 122
by minus 1. 123
So that means that if the user taps a 6, and then taps the "+/-" sign, then that 6 will 124
get passed in as the number, and the "+/-" sign gets passed into this function. 125
And if that is true, then we're going to return 6 126
multiplied by minus 1 as the output of this function. 127
So pause the video and go ahead and fix the last two lines. 128
All right. 129
So it's pretty easy. We just have to follow the format that we had before. 130
So if they tapped on the AC button, then they simply want to change the display to zero. 131
So we'll just return the number zero. 132
And if they've tapped on the percentage button, then the result should be the number multiplied by 0.01. 133
Now, once you get to the button here, it tells you that there's an error: Missing return in a function 134
expected to return Double. 135
Well, you might say that I've got loads of returns here, right? 136
I've got return this, return that, return that. 137
But notice how we have a if statement and two else if statements, 138
there is still a possibility that we get a symbol passed in here that is not "+/-" not "AC," 139
or the "%" sign. 140
So in that case, then this function doesn't actually return anything. 141
And so what we need to do is right at the end, if none of these other cases catches it, then we're simply 142
going to return nil. 143
Now, the next problem is that this function expects us to return a Double, 144
right? 145
And that's not an optional Double, that's just a normal Double, 146
so it can't ever be nil. 147
So in order to be able to return nil, then we have to change this into an optional Double. 148
So there might be certain cases where we pass in a number and we try to perform a calculation on it 149
that doesn't actually match any of these distinct cases that we've addressed. 150
So in that case, we're simply going to return nil and we'll end up with a optional, and we'll deal with 151
the optional on the other side inside the ViewController.swift. 152
So, now that we've got our number, as well as our calculate function done inside our CalculatorLogic class, 153
we can head back to our ViewController and call that function. 154
So inside this "if let," if we actually have a title inside the button that triggered the 155
calcButtonPressed IBAction, then we need to have a new instance of the calculator. 156
So let's create that here. 157
I'm going to create a new let constant called calculator and it's going to be a new instance of our class 158
CalculatorLogic. 159
And when I tried to initialize it, you can see that it's expecting a number to be passed in, and that 160
number is going to be our displayValue. 161
And so when I create my brand-new calculator, then this CalculatorLogic object will be able to have 162
its number property initialized to whatever it is that I pass in here, and then the next step is to call 163
the function that we created inside that object which was called calculate. 164
So calculator.calculate, and the symbol that we want to pass over is this calcMethod because that is 165
equal to the currentTitle of the sender. 166
So let's go ahead and add that in here. 167
And this, remember, has a output and this is what this little warning is telling you, 168
"Result of call to calculate is unused." 169
So what should we do with the result of the calculation? 170
Well, we're going to assign it to our displayValue and we're going to set our displayValue to the calculation 171
result. 172
And remember, we have a didSet in here, 173
so whenever we set this displayValue, then the value will populate our displayLabel. 174
Now, the final thing we need to address is that do you remember how we made the output of our calculate 175
function, a optional Double? 176
Well, we have to deal with the situation where that might be nil, right? 177
So we can simply add in a guard statement and we can say guard let results = calculator.calculate 178
with the symbol, 179
and if this fails, namely, if the result was nil, then we're going to throw a fatalError, 180
and we're going to say, "The results of the calculation is nil," so that we can debug it if necessary. 181
And now we can set our displayValue to results which is now a unwrapped Double, instead of what it used 182
to be which was a optional Double. 183
So let's run our app now and see if that did what we expected it to. 184
All right. 185
So let's try this with some numbers. 186
Let's say 1.2 +/- becomes -1.2, and percentage becomes 0.012, 187
and then AC sets it back to zero. 188
So our code seems to be working just fine, but as we're on the advanced Swift section, it's a good time 189
to think about our app's architecture. 190
Up till now in the course, we've been creating classes for all of our models in our MVC. 191
And this works just fine 192
and makes our code comply with the model-view-controller design pattern that Apple is so fond of, but we 193
can actually make our code a lot safer by simply changing our class into a struct. 194
Now, to create a struct, which is short for a Swift structure, all we have to do is change this keyword 195
from class to struct and this will turn it into a structure. 196
Now, for those you guys who have worked with other programming languages, for example, C or C++ or even 197
Objective-C, you'll think of struct as simply just the way of organizing little bits of data, just simply 198
a way of grouping into related small pieces of data together into a structure. 199
But struct in Swift is a little bit different. 200
And over the years, Swift structures have morphed and changed many, many times, and with every iteration 201
of the language, they've actually added more capabilities, more functionality to these structures to the 202
point where we are right now where they're essentially as capable as any class, and they're no longer 203
these little structures that just groups a little bit of data together. They're very much first-class citizens. 204
You can create properties inside structures. You can create functions inside structures and they can 205
be used absolutely any way, especially for your Data Models. 206
Now, if you look inside the Swift standard library and you look at their definition for a string, for example, 207
you can see that it's actually a struct, and so is a Double, and so are many, many other things that we've 208
grown to rely on in Swift. 209
So let's take a deeper dive into Swift structures and compare them against the classes that we now know 210
and love, and see when we should be using a struct versus a class, 211
and what are the pros and cons of each.