Welcome to Part 2 Dicee in SwiftUI. 1
In the last lesson, we got our app looking exactly the way we wanted to. 2
So, now it's time to add some functionality. 3
For instance, how can we change the dice faces every time the Roll button is pressed. 4
Well, we can start out by going to the top of our ContentView struct and creating some variables. 5
So one variable I'll call the leftDiceNumber set out to equal 1. 6
And I'm also going to create the rightDiceNumber 7
and it's also going to be equal to 1. 8
So these numbers are what I'm going to use to set the image that's in my DiceView. 9
So remember that this "n" property is the one that's going to initialize our image with a particular 10
dice number. 11
So if that end was equal to 1, then that's what we see on screen. 12
If it's equal to five, then it's the dice face with five dots on it. 13
So instead of using the hardcoded one, I'm going to change that to use our variables, leftDiceNumber 14
and rightDiceNumber. 15
So right now, if we refresh our code, you'll see that nothing has changed. 16
It still works exactly as it used to. But our Roll button still doesn't do anything. 17
So remember, previously, I mentioned that the button's action property is the area where we're going to 18
determine what should happen when the button gets pressed. 19
Well, inside this area, we can write some code. 20
So what we want to happen is to generate some random numbers between 1 and 6 to replace the number that's 21
inside the leftDiceNumber and the rightDiceNumber. 22
So inside these curly braces, I'm going to set the leftDiceNumber to equal a random integer, 23
so Int.random. And we've already talked about this in detail in previous modules. All that we need 24
to do is provide a range for our random number generator. 25
So, if we want it between 1 and 6, we would write 1... three dots. and then 6. 26
And now this right-hand side is going to generate a random integer between 1 and 6. 27
So, now notice how as soon as I do that, I get an error from Xcode saying that "self" is immutable. 28
And, of course, we remember from our lesson on struct that structures that we create in Swift are immutable. 29
So it means that whenever we need to change any property, the old copy has to be destroyed 30
and the new copy has to replace it. 31
But in the SwiftUI, we have a special property wrapper which we can use called State. 32
So this is going to allow us to update this variable and to get Swift to recreate this ContentView 33
whenever the value of this variable changes or updates. 34
So now if we go ahead and hit command B to build and effectively refresh our errors, you can see that 35
the old error has gone away and we've now got a new error, and it's telling us that we're trying to set 36
a property inside a closure. And when inside a closure, 37
remember we say that we have to add the "self" keyword in front of all of our properties and methods to 38
be explicit about where this property or method lives. And in this case, it's, of course, in this current 39
struct, 40
so that's why we add the "self" in front. So, now let me go ahead and do the same thing for 41
our rightDiceNumber, also gonna set it equal to an integer which is going to be random, and it's going to be between 42
1 and 6 as well. And, of course, we have to mark the rightDiceNumber property with this @State property 43
wrapper as well. That way SwiftUI will also keep track of this rightDiceNumber and rebuild the 44
structure when it changes. 45
So, now let's go ahead and run our app. 46
And now if you click on the Roll button, you should see that both image views will update to randomly 47
show a number between 1 and 6. 48
And this is all possible because we're creating new random numbers and we're updating our properties. 49
Thanks to the @State Property wrapper. 50
SwiftUI knows that it needs to track leftDiceNumber and rightDiceNumber, 51
then when the number changes, SwiftUI will rebuild the entire ContentView, so that we can see the 52
change on screen. 53
This is a good segue way to talk about how SwiftUI works behind the scenes and manages the state 54
of our app. When we've talked about structs in previous modules, 55
we've seen that we can use the "mutating" keyword to mark the functions that are capable of changing a 56
property in our struct. In SwiftUI, 57
we have to do something similar to the struct properties. We have to use a property wrapper, 58
so this @State 59
to mark properties in our struct that can change. 60
Why do we have to do this though? 61
Well, the answer is that it has to do with how SwiftUI works under the hood. While the Secret Service 62
or Santa keeps a list of who has been naughty and who has been nice, SwiftUI keeps a list of who can 63
change. 64
Every time we mark a property with @State, that property goes on a list, and SwiftUI will monitor that 65
list. And by monitored, I mean SwiftUI will know every time something reads or writes to this property. 66
Therefore, SwiftUI knows which views on the screen are using this property. 67
So if that property changes, SwiftUI knows which views on the screen it also needs to update. 68
Let's talk about this in the context of our code. Inside our container view, leftDiceNumber has been 69
marked with @State, 70
so the system knows that our DiceView struct depends on the value of leftDiceNumber. 71
When we push the Roll button, the state changes. 72
SwiftUI will look at the body of the ContentView and it will recalculate everything. 73
Therefore, SwiftUI will now create a new DiceView from scratch representing those changes. And that's 74
it. 75
We've now built an app that not only has appearance and layout, but also has a functionality, all using 76
SwiftUI. 77
So if any part of this lesson was confusing, I recommend having a review of the lessons where we looked 78
at structures and the immutability of structures. 79
So have a search for that if you need a quick review. 80
But in the next lesson, we're going to be building out our app even further to use more advanced ways 81
of managing state. 82
So for all of that and more, I'll see you there.