Now, in the last lesson, we looked at how Swift tuples work. And now we're able to use it inside this 1
"else if" statement to be able to store the first number of the calculation and also the operation of the calculation. 2
So right at the top here, let's create a brand-new variable that is going to be our intermediate calculation. 3
Now, as a challenge, I want you to create this as a tuple that can store a string and a number that corresponds 4
to the first number that the user is going to calculate with, 5
and also the operation. 6
Now, remember, all of the things that we spoke about in the advanced Swift section and try to create this 7
tuple so that it complies with all of the best practice. 8
Pause the video and give it a go. 9
All right. 10
So here's our tuple up here. 11
And we're not going to give it any values up here 12
when we initialize our structure. 13
So we're only going to specify it's data type. 14
And remember, we specify a tuples data type with a set of parentheses. 15
Now, the first item inside our tuple is going to be the first number. 16
So this is going to be a Double and I'm going to call it n1. 17
Now, the second thing we need to store in here is the calculation method. 18
So I'll just call that calcMethod and this is going to be a String. 19
Now, I don't actually have a value for this tuple 20
when I initialize my CalculatorLogic structure, 21
so I have to be able to set it to nil when I create CalculatorLogic. 22
That means I have to turn it into an optional. 23
And I do that by just adding a question mark to the end of the entire type, 24
right? 25
So in this case, the type is a Double and so the question mark goes at the end of the Double. 26
But in this case, the type of the tuple is all of this, 27
and so the question mark goes right at the end. 28
Now, if instead you'd added the question mark here, 29
then that means you can create tuples that may or may not have an n1. 30
And if you created one here, then that means you can create a tuple that may or may not have an n1 31
or a calcMethod. 32
Now, that's not what we want, 33
so we're going to delete those, too, 34
but we're going to keep the entire tuple as an optional. 35
Now, the final thing to consider is, remember, whenever creating global variables to start it out as a private 36
var, that way we prevent other classes from messing withintermediateCalculation and, certainly, no other 37
class or structure actually needs to be able to modify our intermediate calculation. 38
It's a bit of data that we've saved right in the middle of something we're doing inside CalculatorLogic, 39
so we have to defend it from other people accidentally changing or modifying it. 40
So now that that's done, we can head over into this 41
"else if" and we can set our intermediateCalculation, and I'm going to set it equal to a tuple, 42
so a set of parentheses, and then I'm going to tap into n1. 43
Now, I find that Xcode is not great with autosuggest 44
when it comes to tuples, 45
so I like to type it out just manually. 46
Now, n1 is going to be the number that got passed over with the calculation, 47
so that is equal to n. 48
And then the next thing is the calcMethod. 49
And this is simply going to be the symbol that got passed in when this calcMethod was called. 50
So, now we have set our tuple inside this "else if." 51
So that means when a user taps on a number, and then taps on one of the calcButtons, will pass over 52
the number as well as the calculation method over to our CalculatorLogic. 53
And then it's caught inside here 54
if it was a plus sign that they pressed. aAnd we save that plus sign along with the number inside our 55
tuple. 56
That's called intermediateCalculation for later use. 57
Now, at this point, Xcode, again, tells you that self is immutable because we're inside a struct and 58
we're changing one of the properties here, 59
so therefore, we have to mark this as mutating. 60
So in order to succeed at this challenge, you actually have to have remembered a lot of the things that 61
we discussed in this module. 62
So if any of those things were at all confusing, be sure to have a look back at some of the lessons previously 63
where we discussed access levels or structs and classes and some of the advanced Swift best practice. 64
So, now we have to address what should happen when the user finally presses the equals button. 65
Well, at this point, we should trigger the entire calculation and use what we saved inside the intermediate 66
calculation, 67
right? 68
So let's go ahead and call another method in here which we'll call 69
performTwoNumberCalculation. And this method is only going to have one input and that is going to be the second 70
number that we're performing the calculation with which is, again, going to be a Double. 71
So that number, in this case, will be, right? 72
Because when the user has pressed the equal sign, then that means we passed in the second number that 73
they tapped on. 74
So let's go back to our calculator. 75
When I press on 5 and then plus, then the calculate method gets triggered, and we fall into this "else if" 76
bracket where we set our tuple intermediateCalculation to equal the first number that I typed which 77
was the 5, and the calcMethod which is this plus symbol. 78
Now, once that's done, that gets saved and stashed away ready for the next number to come in. 79
And at this point, let's say I press on 3, and then I press equals, and I expect an answer 80
at this point. 81
So then the calculate function gets called again and I catch it inside this "else if" statement because 82
the symbol was the equal sign. 83
And then I call a function that will perform the whole calculation passing in the second number that 84
it needed to add to the first one which happened to be 3 in my example. 85
So let's go ahead and create this function called performTwoNumberCalculation and it expects a parameter 86
called n2 which is going to be a Double, and it's going to return a Double as the outputs. And this 87
functionality is internal to our calculator because it performs the second half of the calculation. 88
And so this shouldn't be called by anybody outside this current structure. 89
So we can mark this method as private as well to prevent from any other classes or structs from accidentally 90
calling it because it will surely create an error. 91
But inside this function, we're going to group together all of our intermediate calculation that we saved 92
into our tuple. 93
So because our tuple is an optional, then we have to unwrap it or use optional binding to check to make 94
sure that we definitely actually have values for it. 95
Because if the user simply pressed the equal sign right at the beginning by accident without having 96
any operations specified or any number specified, we don't want our app to crash, 97
right? 98
So let's create an "if let" and let's say that if let n1 = intermediateCalculation.n1, 99
and then we can do the optional binding calcMethod in the same line by simply adding a comma. 100
So if let n1 = intermediateCalculation.n1, and also let operation equal 101
intermediateCalculation.calcMethod, then and only then do we perform the code inside this block. 102
So you can see that if I split this code into two lines, we are creating two constants. 103
One is called n1, one is called operation. and we're creating it by optionally chaining 104
intermediateCalculation. 105
So we're saying if intermediate calculation is not nil, that's what that question mark says, 106
then tap into the n1 value inside it and bind it to this thing called n1. 107
And if intermediateCalculation is not nil, again, grab the calcMethod out of it and assign it to our 108
operation. 109
So now that we've got n1 and operation, both unwrapped as non-optionals, we know that they're definitely not 110
nil, 111
then, in this case, we can complete our calculation. So we can say that if the operation was equal to plus, 112
then in that case, we should return as the output n1 + n2, 113
and that is our addition functionality. 114
So if we have a look back at our "if" statement over here, it doesn't make sense to check for plus, minus, 115
times, multiply, divide over here if we can do it separately over here. 116
So what I'm going to do is I'm going to cut that "else if" statement and I'm going to put it in as an "else" 117
instead. 118
So that means that if the symbol that was passed over was not any of these simple calculations, and it 119
wasn't an equals, then everything else, namely, plus, minus, multiply, divide, should be caught inside here 120
and we should create an intermediateCalculation, because everything else that remains other than these 121
three and this button is going to be a two-number calculation. And we're going to store the actual symbol 122
inside this calcMethod inside our tuple. 123
So once the user presses the next number and they press equals to get the result, then we perform our 124
two-number calculation which is a private function, 125
so it can only be called within this current structure, not from outside, 126
and we complete the operation by checking to see which one needed to be performed, and we return the 127
results. 128
So, now Xcode is telling us that this result is not handled over here. 129
So how should we handle it? 130
Well, of course, we're going to return it as the output of this function, 131
right? 132
So as a challenge, I want you to complete this part where we check for all four different operations: 133
plus, minus, multiply, and divide, and specify what should be returned. 134
Now, because we've got four things that we're checking. It doesn't make sense to have it as an "if" statement. 135
So as a part of the challenge, I want you to change this to a switch statement so you can switch on the 136
operation that needs to be performed. 137
So pause the video and go ahead and give that ago. 138
Okay. So let's change this "if" to a "switch" by changing the keyword. 139
Next, let's delete all of this and all of this, so we have a blank switch statement and we're switching 140
on the operation. 141
So let's address some of those cases. 142
In the case where the operation is equal to a plus sign, then we want to return n1 + n2. 143
But in the case where the operation was a minus sign that the user wanted, 144
then we're going to return 145
n1 - n2. 146
Next, if the case was a multiply, and I recommend that to get the symbol for the multiplication, you head 147
over to the Main.storyboard and just double click on that multiply button to copy the text that's in 148
there because unless the unicode is exactly the same, then this won't work. 149
So, now that we've got the multiply symbol in there, we're going to go ahead and return n1 multiplied 150
by n2. And finally, we're going to address the division which, again, I'm going to copy from over here 151
and I'm going to paste it right here. 152
So the last case, we're going to return n1 / n2. 153
And as with all switch statements, you should always have a default case 154
and this just catches out the cases where your operation that's being passed in does not match any of 155
these. 156
And in our case, that would be very, very weird. 157
But we should still catch it and we should throw a fatal error because it's something that should never 158
really happen. 159
And in this case, we're saying that fatal error, the operation passed in does not match any of the cases. 160
So we'll know what's happening at that point. 161
Now, as you can see, we've had this error screaming at us for a little while now, and it's saying that we're 162
missing a return statement in a function that's expected to return Double. 163
Now, you can see we've got lots of return statements, right? 164
So why are they being so hard on us? 165
Well, it's because we've got these "if lets." 166
And that means that there's cases when these would fail. 167
For example, if the user opens up the app and the first thing they do is they tap on the equal sign, 168
well, in that case, we're going to call our performTwoNumberCalculation and there might not even be 169
an intermediateCalculation yet, 170
right? 171
Just because they tapped on it by accident. 172
Well, in this case, we shouldn't crash the app, 173
we should instead just ignore it. 174
So how do we do that in code? 175
Well, we can simply return nil because there is nothing to perform our two number calculation with. 176
Now, in order to be able to return nil, 177
we can't specify that this method only can output Doubles. 178
It has to be able to output optional Doubles, so that we can return it as a nil. 179
So in this case, if they accidentally tapped on the equal sign, we call performTwoNumberCalculation, 180
this turns into nil, 181
we return nil as the output to our calculateMethod. 182
And over here, we catch that inside this "guard" statement which if you notice is, again, 183
a fatalError which will crash on app. 184
So this is a really good point to talk about what is the difference between a "guard let" and an "if let" 185
because you'll see them all over the place in a lot of the Swift code out there in the wild. 186
But it's really difficult for an intermediate or beginner's programmer to understand just when to 187
use a "guard let" versus an "if let." 188
And this is a perfect illustration. 189
Well, in this case, when you use a "guard let," it means that you're guarding against something terrible, right? 190
In very few cases, 191
do you expect this "else" to be triggered? 192
That's what a "guard let" is used. 193
We're guarding against really bad things from happening. 194
That should never really happen unless we had some sort of brain freeze and we completely screwed up 195
our code. 196
Now, if we're using an "if let" instead, then that means that we're expecting that nine times out of ten, 197
this will not be nil and we will be able to trigger this block inside here. 198
But we're also accepting that sometimes it might just be nil and that's fine. 199
We don't have to do anything. 200
We can simply ignore those cases. 201
So, now that I've changed that "guard let" to an "if let" and only when I get a non-nil value from my calculation 202
do I update my displayValue, 203
then it means that if I've accidentally-- then that means that if the user has accidentally tapped on the 204
equal sign without any prior numbers or prior operations, then we don't crash our app, 205
instead our code just ignores it. 206
So this is a really good illustration of why you would use "guard let" versus "if let." And I recommend that 207
if you really want to get down to the nitty-gritties of it, try changing it around and run the app and 208
see what happens for yourself, 209
just so that you can get first-hand experience of what I'm saying to you. 210
All right. 211
So our app is pretty much done, the last thing that I'm going to change is just to make the set of "if" statements 212
into a "switch" statement just to clean up our code. 213
So, now we're ready to test our app and see if it works exactly the way we expect it to. 214
So let's try 9 x 2 = 18 + 6 = 24 / 4 = 6. 215
Clear 216
and percentage. Everything works perfectly. 217
Now, there's a lot more that you could do to this calculator by adding extra buttons, extra functionality, 218
you could make it into a graphing calculator if you really wanted to or you could make it more robust 219
and more reliable in terms of the code as well. 220
But I hope that this has been a fun and interesting project. And along the way, we've learned about access 221
levels, struct versus classes, mutating functions, how to use the "self" keyword, internal and external parameter 222
names, swift tuples, and so much more. So as you can see, it's a jam-packed lesson full of advanced concepts. 223
So, now that you've reached this stage in your development journey, it's really important that if there's 224
anything that you don't fully understand, or if there's something that you want to learn more about, then 225
be sure to do some extra reading, and especially by reading through the Swift Programming Language Online 226
Book which you can access at docs.swift,org/swift-book, and you can look through it and 227
read up on the parts that we've covered, and try it out yourself just so that you can make all of the 228
knowledge in the tutorials your own. 229
So it's all from me, Angela@theAppBrewery. 230
So till next time, guys.