0
1
00:00:02,290 --> 00:00:05,670
Let's take a look at our view controller as it is at the moment.
1

2
00:00:05,680 --> 00:00:11,740
Notice how as we're adding more and more code, the role of the view controller is expanding and becoming
2

3
00:00:11,740 --> 00:00:13,290
less well-defined.
3

4
00:00:13,300 --> 00:00:19,690
For example, our view controller is calculating the BMI, as well as rounding the BMI to one decimal place.
4

5
00:00:19,720 --> 00:00:26,800
So this is a good place to pause and reconsider how we're organizing our code. Our Apple only get more
5

6
00:00:26,800 --> 00:00:33,450
and more complex going forwards. In the final version of our BMI calculator,
6

7
00:00:33,560 --> 00:00:41,060
we're able to change the height and weight. And depending on the BMI that gets calculated will end up
7

8
00:00:41,090 --> 00:00:46,480
with a different colored background and some different advice text.
8

9
00:00:46,630 --> 00:00:53,090
So if we think about how we would organize this information, the advice, the BMI and the background color,
9

10
00:00:53,510 --> 00:01:00,050
well, that seems like it's very much within the "M" of the MVC. And that's what we're going to do in this
10

11
00:01:00,050 --> 00:01:05,510
lesson. We're going to refactor our code to bring it in line with the MVC design pattern.
11

12
00:01:05,510 --> 00:01:13,320
The first thing we should do is, therefore, create our "M" or the model. And there it is in our project, we've
12

13
00:01:13,320 --> 00:01:16,150
already created a Model folder for you.
13

14
00:01:16,200 --> 00:01:22,480
So all we have to do is right-click on it and create a new file inside.
14

15
00:01:22,550 --> 00:01:28,800
Now, in this case, we're going to be creating a new Swift file. And then we're going to call this file
15

16
00:01:28,860 --> 00:01:36,820
CalculatorBrain because it's gonna be responsible for handling all of the logic of calculating our
16

17
00:01:36,820 --> 00:01:37,440
BMI.
17

18
00:01:38,200 --> 00:01:45,220
So inside this new file, I want you to create a new struct called calculatorBrain. So see if you can
18

19
00:01:45,220 --> 00:01:46,330
remember how to do that.
19

20
00:01:46,420 --> 00:01:49,510
Or if not, take a look at the Swift Cheat Sheet to remind you.
20

21
00:01:53,640 --> 00:01:55,650
Now, of course, to create a new struct,
21

22
00:01:55,650 --> 00:02:01,770
we need the struct keyword, and we can even use the code snippet from Xcode to help us.
22

23
00:02:01,770 --> 00:02:08,010
The struct name is going to be CalculatorBrain. And inside the calculatorBrain,
23

24
00:02:08,010 --> 00:02:15,690
We're going to create all of the properties and methods that are required to calculate our BMI to interpret
24

25
00:02:15,690 --> 00:02:20,130
our BMI, provide advice, and provide the appropriate color.
25

26
00:02:20,130 --> 00:02:27,060
So now if we go into our CalculateViewController, let's rip out all of the parts which it's not supposed
26

27
00:02:27,060 --> 00:02:35,880
to be doing.so including the bmiValue, as well as the calculation, and also turning into a string part.
27

28
00:02:36,390 --> 00:02:46,800
And instead, we're going to create a new object called calculatorBrain from our calculatorBrain struct
28

29
00:02:47,250 --> 00:02:50,650
and initialize it with our set of parentheses.
29

30
00:02:50,700 --> 00:02:58,250
Now that we've got access to this calculatorBrain object, we're going to go down into our calculatePressed
30

31
00:02:58,260 --> 00:03:10,140
method, and we're going to say calculatorBrain.calculateBMI. And we're going to pass over the height
31

32
00:03:10,410 --> 00:03:15,340
as one of the inputs and weight as one of the other inputs.
32

33
00:03:15,360 --> 00:03:22,200
Now, this will give us an error right now, but don't worry about it for now. And down here instead of getting
33

34
00:03:22,200 --> 00:03:29,010
the bmiValue which doesn't exist anymore which is why it's saying, "Use of unresolved identifier." We're going
34

35
00:03:29,010 --> 00:03:36,220
to get out calculatorBrain to provide that value, so we'll call getBMIValue.
35

36
00:03:36,330 --> 00:03:42,600
Now, of course, we don't have these methods yet. We don't have a calculateBMI that takes a height and a
36

37
00:03:42,600 --> 00:03:46,650
weight, and then later on it's able to fetch the BMI for us.
37

38
00:03:47,070 --> 00:03:49,020
Well, that is the challenge for you.
38

39
00:03:49,050 --> 00:03:57,780
So pause the video and see if you can make these two errors go away without writing any code inside
39

40
00:03:57,780 --> 00:03:59,190
the view controller,
40

41
00:03:59,190 --> 00:04:06,240
other than these two lines, as well as initializing the calculatorBrain. So keep the code exactly as
41

42
00:04:06,240 --> 00:04:07,500
I have here.
42

43
00:04:07,740 --> 00:04:15,840
And by changing the CalculatorBrain, let's see if you can make this code work and make our error go away.
43

44
00:04:15,840 --> 00:04:17,000
Pause the video now.
44

45
00:04:23,640 --> 00:04:30,630
So the first thing we're going to do is we're going to create this method calculateBMI over in our
45

46
00:04:30,630 --> 00:04:31,680
CalculatorBrain.
46

47
00:04:31,680 --> 00:04:40,320
So let's create a function called calculateBMI and the height needs to be a Float variable, and the
47

48
00:04:40,320 --> 00:04:43,030
weight also needs to be a Float.
48

49
00:04:43,320 --> 00:04:47,700
And then, once those things are passed in, we're going to calculate the BMI.
49

50
00:04:47,700 --> 00:04:55,410
So let bmi equal the weight, divided by height, times height.
50

51
00:04:55,470 --> 00:04:59,750
Now, that we've got the BMI calculated, well, that error will disappear.
51

52
00:05:00,360 --> 00:05:02,030
So let's address the next one.
52

53
00:05:02,040 --> 00:05:05,340
So we also need a method called getBMIValue,
53

54
00:05:05,340 --> 00:05:12,560
so I'm going to copy that. And it should be able to provide us a value in the form of a string,
54

55
00:05:12,570 --> 00:05:16,490
because in our ResultViewController, we're expecting a string.
55

56
00:05:16,560 --> 00:05:19,960
So we need to make this method inside our CalculatorBrain.
56

57
00:05:20,490 --> 00:05:29,850
So let's go ahead and create a method called getBMIValue and it, of course, has to return or output
57

58
00:05:30,000 --> 00:05:32,190
a string data type.
58

59
00:05:32,190 --> 00:05:37,970
So how do we get hold of this BMI value that was calculated in this other method?
59

60
00:05:38,040 --> 00:05:45,480
Well, why don't we go ahead and create a property for our struct, our CalculatorBrain? Let's call it BMI
60

61
00:05:45,870 --> 00:05:55,110
and let's make it a floating point number which is equal to 0.0 to begin with.
61

62
00:05:55,110 --> 00:06:04,050
Now, instead of creating this BMI here as a constant, we're simply going to set this BMI to be equal to
62

63
00:06:04,050 --> 00:06:06,180
the calculated BMI.
63

64
00:06:06,390 --> 00:06:13,320
Now that it's stored in this variable, we can get hold of it in our function here, and we can format it
64

65
00:06:13,410 --> 00:06:18,900
so that we end up with a bmiTo1DecimalPlace.
65

66
00:06:18,900 --> 00:06:23,550
Now, you can, of course, choose a less wordy name than I have, but I just want to make sure that when you
66

67
00:06:23,550 --> 00:06:30,570
look at this, you know exactly what it's trying to do. And this is going to be a formatted string which
67

68
00:06:30,570 --> 00:06:36,060
is going to be accurate to one decimal place,
68

69
00:06:36,060 --> 00:06:43,680
so "%.1f" And then we're gonna pass in the value of BMI as a float, and we should end up with a string
69

70
00:06:43,740 --> 00:06:46,090
which we can use as the output,
70

71
00:06:46,110 --> 00:06:49,500
so returning our BMI to one decimal place.
71

72
00:06:49,650 --> 00:06:54,480
Now, the final problem we have is that we get the error, of course,
72

73
00:06:54,480 --> 00:07:02,640
BMI is a property of our struct and because struct are immutable, in order to change it, we must destroy
73

74
00:07:02,640 --> 00:07:04,680
the old copy and create a new one.
74

75
00:07:04,710 --> 00:07:12,840
So we have to mark this method that changes our property as mutating. And now we should be able to take
75

76
00:07:12,840 --> 00:07:19,200
a look at our CalculateViewController. All of the errors should go away and if we run an app, we should
76

77
00:07:19,200 --> 00:07:23,940
have exactly the same values as before.
77

78
00:07:23,940 --> 00:07:25,800
And that's the solution to the challenge.
78

79
00:07:25,860 --> 00:07:31,740
We're now calculating the BMI in a separate struct and we're returning the BMI to the
79

80
00:07:31,740 --> 00:07:34,110
CalculateViewController as a string.
80

81
00:07:34,110 --> 00:07:39,780
Now, let's take a closer look at our struct. In particular, let's think a little bit more carefully about
81

82
00:07:39,780 --> 00:07:48,930
how we're handling this BMI property. Currently, our BMI property in our calculated brain has a default
82

83
00:07:48,930 --> 00:07:57,000
value of 0.0 to begin with. And we did this because when our CalculatorBrain object gets
83

84
00:07:57,060 --> 00:08:06,660
initialized from this struct, we must have a value for this BMI property. We can either do it here or
84

85
00:08:06,720 --> 00:08:15,120
if we simply declared it as a float data type, well, then we would have to initialize it when we create
85

86
00:08:15,180 --> 00:08:22,260
our CalculatorBrain right here. And round about now, I'm going to get an error right here saying, "Missing
86

87
00:08:22,290 --> 00:08:29,070
an argument for the parameter 'bmi.'" But if you think about it at this point in time, I don't actually know
87

88
00:08:29,070 --> 00:08:35,340
what the BMI is, because I have to wait for the user to toggle the sliders, then press the calculate button
88

89
00:08:35,730 --> 00:08:37,520
before I can actually get a value.
89

90
00:08:38,130 --> 00:08:45,090
So it really doesn't make sense to provide a value for the BMI when we initialize it.
90

91
00:08:45,210 --> 00:08:52,980
So how can we represent this a little bit better? In reality, what this BMI value really should be is
91

92
00:08:53,190 --> 00:09:00,240
it should really be equal to nil to begin with, and only when we actually calculate the BMI should it
92

93
00:09:00,240 --> 00:09:06,990
actually get a value. So does this remind you of something when we have to work with nil values? Of course,
93

94
00:09:07,020 --> 00:09:15,730
we need to turn this into an optional. But as soon as BMI becomes a optional floating point number, well,
94

95
00:09:15,820 --> 00:09:24,070
we've got errors down the line. And previously, all that we've done is simply to just force unwrap when
95

96
00:09:24,100 --> 00:09:25,360
it's safe to do so.
96

97
00:09:26,020 --> 00:09:34,390
But in this case, is it really safe to unwrap this BMI? Because right now, if this method getBMIValue
97

98
00:09:34,390 --> 00:09:40,930
gets triggered before this method, where we actually feel the BMI with a value, at this point, it's still
98

99
00:09:40,930 --> 00:09:41,500
nil.
99

100
00:09:41,950 --> 00:09:49,060
So if we're trying to turn a nil value to a one decimal place string, this is going to crash big time
100

101
00:09:49,060 --> 00:09:52,530
on us. And you can confirm this
101

102
00:09:52,530 --> 00:09:59,390
if you simply just go into the viewDidLoad of all CalculateViewController and call that
102

103
00:09:59,410 --> 00:10:03,460
calculatorBrain method code getBMIValue.
103

104
00:10:03,760 --> 00:10:13,240
And right now if I run my app, pretty much as soon as my view loads up, my app is going to crash and, of
104

105
00:10:13,240 --> 00:10:20,950
course, it crashes on this line right here, because "Unexpectedly found nil while unwrapping an Optional
105

106
00:10:20,950 --> 00:10:21,450
value.
106

107
00:10:24,460 --> 00:10:29,660
And we can see right now this BMI value right here is equal to nil.
107

108
00:10:29,770 --> 00:10:38,740
So therefore, this BMITo1DecimalPlace value, of course, is not going to be able to get calculated.
108

109
00:10:38,800 --> 00:10:45,730
So let's go ahead and remove this offending line of code. And we should also remove this exclamation mark
109

110
00:10:45,790 --> 00:10:49,160
which force unwraps this optional.
110

111
00:10:49,300 --> 00:10:52,550
So how can we solve this problem instead?
111

112
00:10:52,600 --> 00:10:56,070
Are there other ways of working with optionals?
112

113
00:10:56,370 --> 00:11:02,010
Well, to learn more about that, head over to the next lesson where we're going to do a Deep Dive on Swift
113

114
00:11:02,100 --> 00:11:02,790
optionals.
