All right. 1
So, now that we've learned all about struct, it's time to come back to our calculator app and finish the 2
rest of the functionality. 3
So firstly, you would have noticed that I've changed the calculator logic from a class to a struct. 4
And from our knowledge about structs, we now know that we don't actually need an initializer for our structs 5
because we get a free one, right? And Xcode won't give us any errors or complaints because we're now using 6
a struct. 7
Now, there's other things that we can improve in our code as well. 8
If you head over to the ViewController.swift, you can see that at the moment, we're initializing a brand-new 9
CalculatorLogic structure every single time the calc button is pressed. 10
Now, that's pretty inefficient. 11
So let's move this out of the IBAction and let's just move it up here for now. 12
So, now that it's outside this function, this is no longer a local variable. 13
It's now a global variable. 14
And that means that unless we change the access level, any other class could access our instance of the 15
calculator and mess with it. 16
That's not what we want. 17
So let's go ahead and add that private keyword which we add in front of all of our global variables 18
by default. 19
Now, the next problem is that Xcode tells us that you cannot use display value within a property initializer 20
because the property initializers run before 'self' is available. 21
Now, what does all of that mean? 22
Well, it means that because this is a global variable, which happens even before viewDidLoad gets called, 23
the Swift compiler can be sure that display value is not nil at the point when you're trying to initialize 24
CalculatorLogic. 25
So depending on how long it takes to initialize the screen to call viewDidLoad, to do all of the prep work, 26
then displayValue may or may not be nil when you're calling this line of code to create a new 27
CalculatorLogic struct. 28
And this means that we can't use it here. 29
So let's fix this. Now, instead of passing in displayValue to initialize our calculator, 30
let's go ahead and delete that, and instead, make our property number an optional. 31
So this means that we can pass in a value to this property at a later point. 32
And when this struct CalculatorLogic gets initialized, this number property can be nil. 33
And that kind of makes sense, right? 34
When you create a brand-new CalculatorLogic, if the user hasn't pressed any of the buttons on the calculator 35
yet, then it shouldn't really have a number, right? 36
But if this number is a Double, then before we use it, we have to check to make sure that it's not nil. 37
So if let n = number, then that means that number is not nil, and we can now use it inside our 38
code by replacing the places where we use number with this unwrapped n which is a double, rather than 39
an optional double. 40
So, now let's get back to our ViewController. 41
Now, at this point, if you have any lingering errors, be sure to hit command B to force your app to build 42
so that any of the errors that are no longer meant to be here gets removed. 43
Now, the next thing I want to change is inside our struct CalculatorLogic.Our number property 44
at the moment is a global variable. 45
And do you remember what we said about global variables? 46
They should always have the private access level by default because, otherwise, this property is accessible 47
from all other classes within our app. 48
And that means that it could get altered or changed or turned to nil intentionally or unintentionally, 49
which is not what we want, because this property number is integral to our CalculatorLogic model. 50
It's nobody else's business. 51
So instead, we can create a function that allows other classes to set the value of this number property. 52
So we can say setNumber, 53
and as an input, we want to be able to pass in a Double. 54
Now, at this stage, I can name my function setNumber(number: Double) and then do this. But that doesn't 55
really read very well, does it? 56
When I call the function, it's going to be something like setNumber number, and it's because this parameter 57
name is completely unnecessary. 58
So as it stands, if I wanted to set the number over here, I would have to call calculator.setNumber, and 59
then pass in the number 60
that I want to pass which will be the displayValue 61
in this case. Now that works, but I don't actually need this parameter name because the name of the method 62
is already explicit enough as to what this method does. 63
So I'd really like to be able to delete this part. Now, in order to be able to call that method like this, 64
then over here, I can add an underbar, and then a space, 65
and you might have seen the syntax across other Xcode projects, especially Apple's example projects. They 66
love doing this. 67
And what this means is that we're setting the external parameter name to be nothing, 68
and we're setting the internal parameter name because you always need one inside to be able to use the 69
thing that got passed in, right, to number. 70
So if I changed this to, I don't know, num, and I have a setNumber, parentheses, num number, then that means 71
my external parameter name is num and my internal name is number. 72
So inside the curly braces, I will refer to the item that was passed into this function as number, and 73
outside of the parameter name, 74
then I would refer to it as num. 75
But we wanted to not have a parameter name. 76
So we're going to change the external one to an underscore. And instead of printing the number that got 77
passed in, we want to set this private property to equal the value that was passed in. 78
Now, in order to achieve that, I would write something like 79
number = number which is really confusing, because which number is which? 80
Which one of my setting? Am I trying to set this number or am I trying to set this number? And you can see, 81
Swift actually gives you an error saying that number is a let constant because it thinks that you're trying 82
to change this value. 83
So what we do in this case? If we wanted to refer to this global property, we can simply say 84
self.number is equal to number. 85
And this means that anybody else who's looking at your code knows that I'm looking for a property inside 86
the current class or the current struct namely inside the curly braces 87
that's called number which is, of course, this one on line 13. And I'm setting it to equal the number that 88
is the local variable which is this one. 89
Now, the next problem we have is it tells us "Cannot assign to property: 90
'self' is immutable. Mark method 'mutating' to make 'self' mutable." 91
So you should be familiar with this already 92
because we saw this when we were learning about struct, because we're creating this function 93
inside our Swift structure. 94
And this line of code modifies one of the properties of the struct. 95
So if you remember, when you use a struct or when you pass around a struct, it does so by copying all 96
of the values. 97
So if this number had a value, say, it was 2, and this method inside the struct actually needs to change the 98
value of this property to, say, 3, then this method has to be marked with mutating. Because this tells a 99
Swift compiler that this method is capable of changing the properties inside the struct. 100
And that means that it knows to make a brand-new copy of the struct 101
when this function is run, so that it can update the property. Now, by doing that, we've created one more 102
problem for ourselves. 103
If you head back over to ViewController.swift, you can see that Xcode gives us an error saying that 104
you cannot use a mutating member on an immutable value because calculator is a 'let' constant. 105
What does that mean? 106
Well, here,we're calling this function called setNumber which, remember, is a mutating function. 107
It changes one of the properties of our struct. And in the last lesson, we spoke about what made structs 108
different from classes, 109
and one of those things was that they have true immutability. 110
So that means that if you create a new structure that is declared as a "let" constant, then you can't change 111
any of the properties inside that struct at a later point. 112
So when we call this function and it changes our property, then this is why Xcode is getting angry at 113
us, because you said that you weren't going to change this calculator ever, 114
right? 115
So Xcode could be really passive-aggressive like that. 116
But let's go ahead and fix it to make it happy because, as we all know, a happy Xcode equals a happy 117
app developer, right? 118
So let's just quickly recap what we've done so far. 119
We've created this global variable that is called calculator and it's a new instance of our struct 120
CalculatorLogic, and we've marked it as private to prevent other classes from messing with our calculator. 121
Now, when one of the calculation buttons gets pressed, then we call the setNumber function which sets 122
the number inside CalculatorLogic to whatever is currently inside the display. 123
So let's say that on our calculator, the user taps on the number 5. 124
At this point in our code, we set the display value to 5. Next, the user taps on the plus sign. 125
And because this is one of the calculate buttons, then our IBAction calcButtonPressed will get called. 126
And inside that IBAction, we call setNumber on our calculator structure and we set the number in the 127
calculator to 5. And then we also call the calculate function passing in that plus sign as the symbol. 128
Next, the user taps on 3. 129
At this point, we set the display value to 3. And finally, they tap on the equal sign. 130
So the calcButtonPressed IBAction gets called yet again, and we set our calculator's number property 131
to 3, and we call the calculate function, again, passing in the symbol equals. 132
So when they tap on the plus button, we need to save that data somewhere in our CalculatorLogic. 133
We need to save the first number that they wanted to calculate and the calculation that they wanted 134
to make which is to add. 135
Now, I could say that all in separate properties, right, up here, 136
or I could create a brand-new struct that contains the first number and the operation they want to make. 137
But that seems a bit overkill. 138
Now, what's in between creating a new struct and creating a simple property? 139
Well, in Swift, we have something called tuples, and that is what we're going to learn about in the next 140
episode. 141
So for all of that and more, I'll see you there.