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