0
1
00:00:00,600 --> 00:00:01,120
Hey, guys.
1

2
00:00:01,140 --> 00:00:04,880
Welcome to another Swift Deep Dive. In this Deep Dive,
2

3
00:00:04,890 --> 00:00:11,250
we're going to look at the difference and the similarities between structs and classes and when you should
3

4
00:00:11,250 --> 00:00:13,410
choose to use each.
4

5
00:00:13,410 --> 00:00:21,030
So previously, we really saw that we could create a class like so. And by simply changing that class keyword,
5

6
00:00:21,390 --> 00:00:22,850
we can create a struct.
6

7
00:00:23,250 --> 00:00:26,660
But, of course, structs are unable to inherit.
7

8
00:00:26,690 --> 00:00:33,300
So they don't have the part that classes have where they're able to specify a SuperClass that they can
8

9
00:00:33,300 --> 00:00:35,280
inherit capabilities from.
9

10
00:00:35,400 --> 00:00:38,280
But there are a lot of similarities, too.
10

11
00:00:38,310 --> 00:00:46,440
So in this class that we've created where we're not inheriting from any SuperClass, it almost looks like
11

12
00:00:46,530 --> 00:00:49,540
a struct. And similar to struct,
12

13
00:00:49,560 --> 00:00:57,390
we're essentially creating a blueprint to be able to group together attributes and behavior into one
13

14
00:00:57,390 --> 00:00:58,530
component,
14

15
00:00:58,530 --> 00:01:06,810
and later on, we can use that blueprint to create an object from it, and we can use it to create as many
15

16
00:01:06,810 --> 00:01:07,350
as we want.
16

17
00:01:07,380 --> 00:01:14,280
So we could spawn, for example, a whole bunch of skeletons simply by tapping into that Class blueprint
17

18
00:01:14,490 --> 00:01:19,490
or a Struct blueprint. Now similar to struct,
18

19
00:01:19,560 --> 00:01:26,550
we also have initializers in classes, so I could delete these default values and simply specify their
19

20
00:01:26,550 --> 00:01:27,420
data type.
20

21
00:01:27,720 --> 00:01:32,880
And these are both gonna be integers, and then I can initialize it.
21

22
00:01:32,880 --> 00:01:38,560
Now, notice how if we have a struct, we get a free initializer.
22

23
00:01:38,580 --> 00:01:45,720
So we don't actually have to write the init method. But if we had a class on the other hand, then we would
23

24
00:01:45,720 --> 00:01:50,530
get an error saying that class enemy has no initializers,
24

25
00:01:50,610 --> 00:01:58,590
so we have to provide the init ourselves, and I will do exactly that. So I'll provide an input code health
25

26
00:01:59,010 --> 00:02:06,690
which has a date type of Int, and then I have another one called attackStrength which is also an Int.
26

27
00:02:06,810 --> 00:02:13,260
And once those inputs get passed in, I'm going to set the self.health which, of course, refers
27

28
00:02:13,260 --> 00:02:20,100
to this current classes health property, which is this one, and I'm going to set it equal to the health
28

29
00:02:20,460 --> 00:02:29,290
that got passed in as the input and I'll do the same with my attackStrength property. And now when I
29

30
00:02:29,290 --> 00:02:38,680
go and initialize my skeletons, for example, let's say create skeleton1, I have to provide those arguments,
30

31
00:02:38,680 --> 00:02:39,150
right?
31

32
00:02:39,190 --> 00:02:45,400
So if we go ahead and create an enemy and open a set of curly braces, you can see both the health and
32

33
00:02:45,400 --> 00:02:53,500
attackStrength parameter expects a value, so that I can initialize the skeleton object from my class
33

34
00:02:53,890 --> 00:02:59,970
and pass in the necessary values for my properties which don't currently have a value.
34

35
00:03:00,280 --> 00:03:07,500
So let's say that the skeleton1 has a health of 100 attack strength of 10.
35

36
00:03:07,510 --> 00:03:15,730
Now, here comes the curious thing. if I go into my enemy class and I create another function, so let's
36

37
00:03:15,790 --> 00:03:17,610
call it takeDamage.
37

38
00:03:18,430 --> 00:03:25,500
So let's say that our enemy got hit, well, then we can specify a damage amount.
38

39
00:03:25,960 --> 00:03:27,450
So let's call that amount,
39

40
00:03:27,460 --> 00:03:28,900
set it as an integer.
40

41
00:03:29,170 --> 00:03:36,130
And then inside the function, we're going to update the health property to deduct the amount of damage
41

42
00:03:36,460 --> 00:03:38,800
that it got dealt.
42

43
00:03:38,800 --> 00:03:46,540
So now when we call the takeDamage method, our enemies health should be reduced by the amount that they
43

44
00:03:46,540 --> 00:03:47,670
got damaged by.
44

45
00:03:48,160 --> 00:03:51,850
And now if I want to create another skeleton,
45

46
00:03:51,850 --> 00:03:58,900
well, if I wanted another skeleton, say, let skeleton2, for example, I want to be exactly the same as
46

47
00:03:58,900 --> 00:03:59,360
skeleton1,
47

48
00:03:59,440 --> 00:04:03,260
so why don't I just set it to equal skeleton1?
48

49
00:04:03,400 --> 00:04:09,760
So looking at this code, it would appear that skeleton2 is a copy of skeleton1.
49

50
00:04:09,910 --> 00:04:14,090
Let's delete the dragon code and investigate if this is indeed the case.
50

51
00:04:14,200 --> 00:04:22,370
Let's see what happens when skeleton1 takes some damage. So skeleton1 took some damage,
51

52
00:04:22,530 --> 00:04:28,570
So .takeDamage. And let's say it got damaged by 10.
52

53
00:04:28,620 --> 00:04:38,910
Now here's a question: If I was to print and get hold of my skeleton2 object and I wanted to access
53

54
00:04:39,000 --> 00:04:43,470
its health property, what do you think that should be?
54

55
00:04:43,470 --> 00:04:51,810
Remember that I copied skeleton2 from skeleton1 at the point where skeleton1 was just initialized,
55

56
00:04:51,840 --> 00:04:58,920
so it had full health, and they got to attackStrength of 10, and then skeleton1 took some damage, but
56

57
00:04:58,920 --> 00:05:00,650
skeleton2 didn't.
57

58
00:05:00,660 --> 00:05:05,840
Nothing happened to skeleton2, it was just sitting around waiting to attack.
58

59
00:05:05,880 --> 00:05:08,880
So what do you think this line would print?
59

60
00:05:09,010 --> 00:05:15,680
And I want you to have a think about it before you run this code because it's quite curious. All right,
60

61
00:05:15,700 --> 00:05:22,020
so if I run the code, you can see that what gets printed is actually 90.
61

62
00:05:22,220 --> 00:05:26,510
Why is it that skeleton2 which didn't take any damage at all,
62

63
00:05:26,510 --> 00:05:28,550
why does it have a health of 90?
63

64
00:05:29,780 --> 00:05:35,300
Well, this is because classes are passed by reference.
64

65
00:05:35,300 --> 00:05:42,910
So here on this line, where I created a copy of skeleton1,  I haven't actually created a real copy,
65

66
00:05:43,040 --> 00:05:49,380
all I've done is I've created another reference to the same object.
66

67
00:05:49,400 --> 00:05:56,960
So this is basically a second reference to the same skeleton object that I initialized here. Had I wanted
67

68
00:05:56,960 --> 00:05:58,820
to create a whole new object,
68

69
00:05:58,850 --> 00:06:06,530
I would have to, essentially, copy this code and initialize a new enemy. For if I did this,
69

70
00:06:06,530 --> 00:06:10,280
you can see that skeleton2 is completely unscathed
70

71
00:06:10,280 --> 00:06:18,560
when skeleton1 takes damage. This is kind of dangerous though, because just by looking at this code,
71

72
00:06:19,040 --> 00:06:23,330
it doesn't look like as if that's what would happen.
72

73
00:06:23,330 --> 00:06:31,520
And this is why classes tend to be considered as more complex and, therefore, more error-prone than struct.
73

74
00:06:31,910 --> 00:06:37,570
Because in the case of a class, this copying behavior is quite unintuitive,
74

75
00:06:37,760 --> 00:06:41,890
and we've now got two references to the same object.
75

76
00:06:42,440 --> 00:06:51,290
And if we manipulate that object from skeleton1, say, take some damage of 10 and we manipulate the
76

77
00:06:51,290 --> 00:06:54,100
object that we think is a separate object.
77

78
00:06:54,170 --> 00:06:55,720
We take some damage.
78

79
00:06:55,770 --> 00:07:04,130
Well, actually, what ends up happening at the end of the day is that both of these things are actually
79

80
00:07:04,130 --> 00:07:06,370
referring to the same thing.
80

81
00:07:06,380 --> 00:07:12,800
So if I go ahead and print my skeleton1.health and skeleton2.health here, you can see
81

82
00:07:12,800 --> 00:07:19,760
that they're both going to be the same, and they actually in total--took a total of 30 damage, even though
82

83
00:07:19,760 --> 00:07:29,010
I thought I was manipulating separate objects. iIf we had instead created a struct, instead of a class,
83

84
00:07:29,060 --> 00:07:37,520
well, firstly, in a struct, we're reminded when we actually mutate our struct and that happens through
84

85
00:07:37,520 --> 00:07:43,740
this mutating keyword. Because this function will update a property of the struct,
85

86
00:07:43,910 --> 00:07:51,980
it alerts us to this fact already, and we won't be able to do this without making it mutating because,
86

87
00:07:51,980 --> 00:07:55,980
remember, struct are immutable.
87

88
00:07:56,050 --> 00:08:01,780
Now, when this function happens, the old struct gets destroyed and a new one with the updated value gets
88

89
00:08:01,780 --> 00:08:03,220
created.
89

90
00:08:03,280 --> 00:08:11,970
But when I make a copy of a struct, it really does make a whole new copy and they're completely separate.
90

91
00:08:11,980 --> 00:08:19,170
So now if I tried to run this code, it gives me another reminder that this struct is gonna be changed.
91

92
00:08:19,210 --> 00:08:26,000
It says that "Cannot use mutating member on immutable value: 'skeleton1' one is a 'let' constant.
92

93
00:08:26,020 --> 00:08:29,310
So this is a constant and this is a constant.
93

94
00:08:29,320 --> 00:08:37,060
So when we run that takeDamage as to destroy the old object and create a new one in its place, but because
94

95
00:08:37,060 --> 00:08:42,400
we have created a constant here with the "let" keyword, it is not able to do that,
95

96
00:08:42,400 --> 00:08:50,560
so we have to change this to "vars." But now if I try to run my code, the first thing you'll notice is that
96

97
00:08:50,650 --> 00:08:54,350
I lose my capability of inheritance.
97

98
00:08:54,460 --> 00:09:02,410
So my Dragon class has to be commented out because Enemy is now a struct and it can no longer be a SuperClass
98

99
00:09:02,590 --> 00:09:05,950
or inherit from any class.
99

100
00:09:05,950 --> 00:09:12,990
But if we're still looking at our main.swift here and I run my code, you can see that skeleton1's
100

101
00:09:13,000 --> 00:09:22,230
health went down to 80 because it took 10 damage on line 5 and line 8. And skeleton2's health,
101

102
00:09:22,240 --> 00:09:29,740
the one that was printed second, actually only took 10 damage, so it still has a health of 90.
102

103
00:09:29,830 --> 00:09:39,550
So now you can see that our struct is being copied and skeleton2 is no longer a reference to the same
103

104
00:09:39,580 --> 00:09:42,040
object that was created in skeleton1.
104

105
00:09:42,160 --> 00:09:48,700
It's, in fact, a completely separate copy which means that when I do things to it, it doesn't affect my
105

106
00:09:48,700 --> 00:09:51,230
skeleton1 on my previous copy.
106

107
00:09:51,340 --> 00:09:58,540
And so this makes it much simpler to understand the side effects and what might happen when I manipulate
107

108
00:09:58,540 --> 00:10:00,530
these objects.
108

109
00:10:00,700 --> 00:10:09,350
One of the biggest differences between struct and classes is that struct are passed around by value.
109

110
00:10:09,430 --> 00:10:17,170
So what that means is that if I had a photo and I wanted to give it to you, then I could make a copy of it
110

111
00:10:17,590 --> 00:10:20,200
and give you that copy.
111

112
00:10:20,320 --> 00:10:24,940
Now, classes, on the other hand, are passed by reference.
112

113
00:10:24,940 --> 00:10:32,950
So if I wanted to give you access to my photo, I would tell you where my photo is located, so I can give
113

114
00:10:32,950 --> 00:10:35,400
you the location of it on my computer.
114

115
00:10:35,800 --> 00:10:43,360
I could say it's under Users/angelayu/desktop/photo.jpeg, and you'll find it there.
115

116
00:10:43,420 --> 00:10:53,310
Now, the problem occurs when lots of people need access to the same resource. Now in the case of a struct,
116

117
00:10:53,760 --> 00:10:57,480
if lots people have multiple copies of the same thing,
117

118
00:10:57,870 --> 00:11:00,520
well, if they destroy their copy of it,
118

119
00:11:00,600 --> 00:11:03,510
say, you decide to draw whiskers onto my face
119

120
00:11:03,510 --> 00:11:05,370
in this lovely photo that I gave you,
120

121
00:11:05,880 --> 00:11:08,790
well, you've only just destroyed your own copy.
121

122
00:11:09,090 --> 00:11:12,300
Everybody else's copy is unaffected.
122

123
00:11:12,300 --> 00:11:19,020
Now, on the other hand, if lots of people had access to the same resource based on a reference,
123

124
00:11:19,050 --> 00:11:22,200
so they all knew where it was on my computer,
124

125
00:11:22,200 --> 00:11:25,370
and one of them accidentally deletes it,
125

126
00:11:25,380 --> 00:11:27,730
well, that's kind of it for all of us.
126

127
00:11:27,780 --> 00:11:38,430
We've all lost that resource now. So that's why Apple advises that you always default to creating a struct.
127

128
00:11:38,440 --> 00:11:45,450
So start by creating a struct whenever you need that blueprint to create new objects.
128

129
00:11:45,550 --> 00:11:52,390
But if you find that you need inheritance or you need to work with old Objective-C code, then you can
129

130
00:11:52,390 --> 00:11:55,660
simply turn your structure into a class.
130

131
00:11:56,020 --> 00:12:00,150
So that wraps up our Deep Dive on structures and classes.
131

132
00:12:00,190 --> 00:12:05,140
And to recap, here's a brief summary of some of the things that we talked about.
132

133
00:12:05,140 --> 00:12:11,020
Structures are immutable, meaning that every change that you make to the structure involves destroying
133

134
00:12:11,020 --> 00:12:13,900
the old copy and creating a new one.
134

135
00:12:13,900 --> 00:12:22,000
In addition, we saw how structures are passed by value. So it's passed around by the actual value that's
135

136
00:12:22,000 --> 00:12:24,670
held. Now, in comparison,
136

137
00:12:24,790 --> 00:12:31,390
classes are passed by reference, meaning that we can have more than one variable that points to the same
137

138
00:12:31,450 --> 00:12:32,020
object,
138

139
00:12:32,590 --> 00:12:37,140
and we're simply passing around the reference to that same object.
139

140
00:12:37,630 --> 00:12:42,130
In addition, classes have the ability to inherit from other classes.
140

141
00:12:42,130 --> 00:12:48,430
This means that we can use inheritance to add additional functionality to SubClasses as we saw with
141

142
00:12:48,430 --> 00:12:50,490
the components of Apple's UIKit.
142

143
00:12:51,100 --> 00:12:57,640
So if you'd like to learn more about structures versus classes or read about each of those in more detail,
143

144
00:12:58,030 --> 00:13:02,980
I recommend heading over to this page in the Swift Programming Language Guide and taking a look at it.
144

145
00:13:04,000 --> 00:13:09,640
So, a link to this page,and you can get more of a background on structures and classes.
