0
1
00:00:00,480 --> 00:00:10,410
In the last few lessons, we've managed to create a Weather Manager object which is able to perform the
1

2
00:00:10,470 --> 00:00:15,140
networking that fetches the live data from OpenWeather Map,
2

3
00:00:15,300 --> 00:00:24,310
and then we're able to pass the weather into an actual Swift object which we can access in a Swifty
3

4
00:00:24,330 --> 00:00:26,810
format like this.
4

5
00:00:26,910 --> 00:00:34,500
In this lesson, I want to focus on getting hold of our weather conditions because we need to be able
5

6
00:00:34,500 --> 00:00:40,470
to update this image view with a different image from the system's
6

7
00:00:40,470 --> 00:00:45,300
SF icons, so that it represents the condition of the weather.
7

8
00:00:46,700 --> 00:00:53,450
Now, if we take a look at the API doss for OpenWeather, you can see that they've got this section on
8

9
00:00:53,570 --> 00:01:03,620
list of condition code. And this section here links to all of the condition codes that they use, and that
9

10
00:01:03,620 --> 00:01:09,110
refers to the ID property in the data that we get back.
10

11
00:01:09,890 --> 00:01:12,790
What do these IDs actually correspond to?
11

12
00:01:12,920 --> 00:01:16,800
Well, they're a way of encoding different weather conditions.
12

13
00:01:16,940 --> 00:01:23,780
So, for example, everything from 200 to 232, encode some sort of thunderstorm, and there's
13

14
00:01:23,840 --> 00:01:27,850
apparently different types of thunderstorms which I didn't really know about,
14

15
00:01:27,920 --> 00:01:32,070
like a ragged thunderstorm. I don't want to be in one of those.
15

16
00:01:32,120 --> 00:01:40,460
Now, we know that we can get hold of the ID which is the ID of the weather condition and we can match
16

17
00:01:40,460 --> 00:01:46,440
it against these values to see what type of image we should show the user.
17

18
00:01:47,270 --> 00:01:53,870
So let's go ahead and do that. Instead of getting hold of the description which we're not actually gonna
18

19
00:01:53,890 --> 00:01:54,800
use,
19

20
00:01:54,920 --> 00:02:02,930
instead, I'm going to change this property to "id" and the "id" is an integer data type. And I can do
20

21
00:02:02,930 --> 00:02:09,920
this because the "id" is actually nested inside at the same level as the description.
21

22
00:02:09,980 --> 00:02:17,480
So changing that over from the description to the "id" or you can if you want to just simply added on
22

23
00:02:17,630 --> 00:02:24,710
as an additional property if you plan on using the description at some later stage. But they both live
23

24
00:02:24,770 --> 00:02:32,510
within this Weather struct which is an array of weather conditions that we're getting back which comes
24

25
00:02:32,510 --> 00:02:34,650
from the entire WeatherData.
25

26
00:02:34,670 --> 00:02:40,910
So following it down, this is the first property which goes into an array, which then has an object with
26

27
00:02:40,940 --> 00:02:42,280
a property code "id."
27

28
00:02:42,350 --> 00:02:47,650
So quite convoluted, but eventually, we should be able to get a hold of this number.
28

29
00:02:47,710 --> 00:02:54,790
Let's go ahead and try to print that in our WeatherManager just to make sure that it's actually working.
29

30
00:02:56,590 --> 00:03:03,490
So let's see what it's like in Bali at the moment. And the weather condition code I'm getting back is
30

31
00:03:03,580 --> 00:03:04,900
803.
31

32
00:03:04,900 --> 00:03:13,940
And if I check against this table 803 is broken clouds, 51 to 84 percent.
32

33
00:03:13,960 --> 00:03:14,950
Interesting.
33

34
00:03:14,950 --> 00:03:21,280
So in this case, I would probably just show a cloud in my app right here.
34

35
00:03:21,370 --> 00:03:29,770
So this is the perfect opportunity to utilize what you've learned about Swift switch statements a few
35

36
00:03:29,770 --> 00:03:30,920
modules back.
36

37
00:03:31,210 --> 00:03:39,590
So I'm going to set this to you as a challenge. Given that we have this ID which I'll call 
37

38
00:03:39,640 --> 00:03:41,370
let id = decodedData.weather [0].id,
38

39
00:03:41,380 --> 00:03:50,050
I want you to create a function down here that we'll call
39

40
00:03:50,170 --> 00:03:58,660
getConditionName, and it takes the input in the format of the weatherId which is going to be an integer,
40

41
00:03:59,500 --> 00:04:07,300
and then inside this function, we're going to return a String. And that string will depend on the Weather
41

42
00:04:07,300 --> 00:04:07,940
ID.
42

43
00:04:08,170 --> 00:04:16,420
So we're going to call this getConditionName and pass in the id right here that we get back,
43

44
00:04:16,420 --> 00:04:24,850
and then inside this method was somehow going to use a switch statement to output a string, and that string
44

45
00:04:24,910 --> 00:04:29,520
should match the name of one of these symbols.
45

46
00:04:29,530 --> 00:04:36,550
So, for example, if we were getting clouds, then maybe we would simply return the word "cloud" which would
46

47
00:04:36,550 --> 00:04:39,310
match with this image's name.
47

48
00:04:39,490 --> 00:04:47,320
And if we got, say, rain then maybe we would put cloud.rain to get this symbol. Because, eventually,
48

49
00:04:47,320 --> 00:04:55,130
what we're going to do is we're going to be using that condition name to change this image view here.
49

50
00:04:55,150 --> 00:05:01,990
So if we got cloud.rain as the condition name, that's what we would see. If we got just a cloud,
50

51
00:05:01,990 --> 00:05:10,260
then we would get this image. If we got sun.max, then we would get this image.
51

52
00:05:10,260 --> 00:05:18,210
So feel free to pick and choose whichever icon takes your fancy as long as they more or less match the
52

53
00:05:18,240 --> 00:05:23,320
condition name that we're getting back from Open Weather Maps table.
53

54
00:05:23,550 --> 00:05:30,750
And then when you get this condition name back, I want you to go ahead and print it, so that when you
54

55
00:05:30,810 --> 00:05:38,010
run the app and you put in the name of a location, say in Paris, and you go ahead and get the weather
55

56
00:05:38,010 --> 00:05:45,630
for it, you should be able to get a name for a SF symbol that matches the weather condition of that
56

57
00:05:45,630 --> 00:05:47,310
location.
57

58
00:05:47,340 --> 00:05:52,800
Now, if you already know all about the Swift switch statements and you don't want to complete this challenge,
58

59
00:05:53,130 --> 00:05:58,920
then you can also head over to the README file and you'll find the switch statement already written
59

60
00:05:58,920 --> 00:06:03,350
for you. But I recommend that more practice is always good.
60

61
00:06:03,390 --> 00:06:10,020
So using a Switch statement, try and print out the name of an icon that matches the condition ID from
61

62
00:06:10,050 --> 00:06:11,330
OpenWeather Map.
62

63
00:06:11,370 --> 00:06:18,470
I'm going to leave it up to you to pause the video and complete the challenge if you want to. All right.
63

64
00:06:18,500 --> 00:06:26,660
So here's our Switch statement. And it looks at the weatherID that we get passed over and takes a
64

65
00:06:26,660 --> 00:06:35,540
look at its value, and tries to match it against these cases, and these cases I've put in as ranges.
65

66
00:06:35,570 --> 00:06:42,830
So the range between 200 and 232 in the weather condition codes matches a thunderstorm.
66

67
00:06:43,400 --> 00:06:50,210
So out of all of these pictures of thunderstorms, I think the cloud.bolt looks quite nice.
67

68
00:06:50,390 --> 00:06:58,550
So I've decided to return cloud.bolt, and I've done basically the same thing to match all of these
68

69
00:06:58,640 --> 00:07:00,310
different conditions.
69

70
00:07:00,830 --> 00:07:06,770
And in the default condition where none of these cases match, then I'm just gonna return cloud as the
70

71
00:07:06,770 --> 00:07:09,630
default option.
71

72
00:07:09,660 --> 00:07:16,650
Now, if you are at all confused about Switch statements or the range operator, then be sure to head back
72

73
00:07:16,650 --> 00:07:23,010
to some of those Swift Deep Dives where we talked about those things in more detail. And that's the solution
73

74
00:07:23,010 --> 00:07:31,660
to the challenge. But now you might be noticing that this file is getting a little bit messy and we're
74

75
00:07:31,660 --> 00:07:40,780
getting to the point where we kind of need to group some data in a custom data type. And that is, of course,
75

76
00:07:40,840 --> 00:07:43,480
the role of the data model.
76

77
00:07:43,480 --> 00:07:44,880
So let's do that now.
77

78
00:07:44,920 --> 00:07:49,550
Let's reorganize our code in accordance with the MVC design pattern.
78

79
00:07:49,570 --> 00:07:54,550
This means that we'll take some functionality out of the WeatherManager and put it into a separate
79

80
00:07:54,550 --> 00:07:55,330
file.
80

81
00:07:55,330 --> 00:08:02,980
That way, we'll have shorter and simpler files that are easier to understand. If I want to create a custom
81

82
00:08:03,130 --> 00:08:10,480
weather data model which is able to figure out the condition name based on the condition ID, then I
82

83
00:08:10,480 --> 00:08:20,470
would need to go into my Model folder and create a New File which I'm going to call the WeatherModel,
83

84
00:08:22,370 --> 00:08:28,510
and I'm gonna use this file to model what a weather object should look like.
84

85
00:08:28,510 --> 00:08:34,690
Let's create it as a struct and it's gonna be called a WeatherModel and it's gonna have a number of
85

86
00:08:34,690 --> 00:08:35,490
properties.
86

87
00:08:35,530 --> 00:08:42,270
So we definitely need to have a conditionId property which is an Int.
87

88
00:08:42,430 --> 00:08:48,760
We also need to have a city name property which is gonna be a String.
88

89
00:08:48,760 --> 00:08:54,920
And finally, we also need a temperature property which is gonna be a Double.
89

90
00:08:54,910 --> 00:09:01,930
So now I can go ahead and move this functionality of figuring out what the condition name should be
90

91
00:09:02,290 --> 00:09:05,810
based on the condition code or the weatherId.
91

92
00:09:05,860 --> 00:09:10,740
This is very much within the realm of the weather object.
92

93
00:09:10,750 --> 00:09:13,230
So let's go ahead and paste that in here.
93

94
00:09:14,810 --> 00:09:22,130
Now, back inside our Weather Manager. Instead of having all these disparate pieces of information, I can
94

95
00:09:22,130 --> 00:09:33,080
create my ID as my decodedData weatherId. I can create my temperature or temp as the
95

96
00:09:33,230 --> 00:09:36,500
decodedData.main.temp.
96

97
00:09:36,500 --> 00:09:41,700
And finally, I'm gonna create my city name or I'm just gonna call it name for short
97

98
00:09:41,840 --> 00:09:45,560
from the decodedData.name property.
98

99
00:09:45,560 --> 00:09:53,000
So, now that I've got all the properties that I want out of my weather data, I can create myself a weather
99

100
00:09:53,090 --> 00:09:56,120
object from my new WeatherModel.
100

101
00:09:56,780 --> 00:10:02,840
So when we initialize it, we have provide the conditionId which is the ID, the cityName which is
101

102
00:10:02,930 --> 00:10:07,240
name, and the temperature which is temp.
102

103
00:10:07,590 --> 00:10:17,760
Now, if I wanted to get a hold of the ConditionName, then I can simply write weather.getConditionName
103

104
00:10:17,760 --> 00:10:28,680
and I have to pass in the ID. But wouldn't it be nice if I could just have a property in my weather
104

105
00:10:28,680 --> 00:10:35,670
object that's called a condition name and it manages to figure out what that should be.
105

106
00:10:35,880 --> 00:10:43,910
Instead of getting my weather manager to call the method getConditionName, in order to get the ID.
106

107
00:10:44,460 --> 00:10:50,850
This is a good opportunity to show you a cool thing that we can do in Swift which is called a computed
107

108
00:10:50,850 --> 00:10:51,390
property.
108

109
00:10:52,020 --> 00:10:57,960
So we've got all three properties here which are actually called stored properties because all they
109

110
00:10:57,960 --> 00:11:00,840
do is they just store pieces of data.
110

111
00:11:01,200 --> 00:11:04,710
But I can also create a computed property.
111

112
00:11:05,340 --> 00:11:13,200
So I'm going to create it using a var keyword and I'm going to call it the conditionName, and it's going
112

113
00:11:13,200 --> 00:11:21,750
to have a data type of String, and then I'm going to open up a set of parentheses. And inside the set
113

114
00:11:21,750 --> 00:11:30,060
of parentheses, I'm expected to return or output what the value for the condition name should be.
114

115
00:11:30,060 --> 00:11:36,690
That would require me to work out the condition name which, luckily, I've already got down here in the
115

116
00:11:36,690 --> 00:11:38,610
form of my Switch statement.
116

117
00:11:38,610 --> 00:11:48,990
So let's paste that in here and we can use the conditionId property value to switch, and then check
117

118
00:11:49,260 --> 00:11:55,830
what condition it is to return this string which is going to be equal to the conditionName.
118

119
00:11:56,200 --> 00:12:03,870
So, now I've got a computed property because this property condition name is going to work hard
119

120
00:12:03,870 --> 00:12:09,300
its value based on the code inside these curly braces.
120

121
00:12:09,360 --> 00:12:15,660
What this allows me to do is if I want to get hold of the weather condition, all I would have to do is
121

122
00:12:15,660 --> 00:12:23,810
say weather.conditionName and I can use it just like any other property.
122

123
00:12:24,030 --> 00:12:30,200
And if you run your app right now, you'll see it works perfectly
123

124
00:12:30,200 --> 00:12:32,030
just like before.
124

125
00:12:32,030 --> 00:12:40,340
But our code is now a lot better after the refactoring and it's a lot more succinct and easier to understand.
125

126
00:12:40,340 --> 00:12:44,360
So what's a general format for computed properties in Swift?
126

127
00:12:44,360 --> 00:12:49,420
Let's go over the syntax for computed properties again. In order to create a computed property,
127

128
00:12:49,430 --> 00:12:55,550
it always has to be a var because the value is always going to change. It's going to be based on the
128

129
00:12:55,550 --> 00:12:57,000
computation.
129

130
00:12:57,290 --> 00:12:58,810
And then we give it a name,
130

131
00:12:58,820 --> 00:13:04,630
so let's call it aProperty. And then we have to give it a data type,
131

132
00:13:04,670 --> 00:13:07,550
so let's say I want it to be an integer.
132

133
00:13:07,550 --> 00:13:14,660
Now, in between the curly braces, I have to provide an output that is going to be set as the value of
133

134
00:13:14,660 --> 00:13:15,830
this property.
134

135
00:13:15,890 --> 00:13:20,810
So let's say that I wanted to calculate, I don't know, 2 + 5,
135

136
00:13:21,380 --> 00:13:23,380
So this is the computation
136

137
00:13:23,600 --> 00:13:28,730
and that means aProperty is going to be equal to the result of this computation which is going to be
137

138
00:13:28,730 --> 00:13:29,920
7.
138

139
00:13:30,320 --> 00:13:32,870
That's all computed property in Swift.
139

140
00:13:33,170 --> 00:13:41,990
And as practice and as a challenge, I want you to figure out how we can get hold of the temperature as
140

141
00:13:42,050 --> 00:13:46,160
a string with only one decimal place.
141

142
00:13:46,160 --> 00:13:49,740
So you've done this before using the string initializer,
142

143
00:13:50,000 --> 00:13:57,190
but I want you to turn that into a computed property now, and it should be called temperatureString.
143

144
00:13:57,470 --> 00:14:03,410
And if you manage to successfully solve the challenge, then you should be able to print
144

145
00:14:03,590 --> 00:14:12,790
weather.temperatureString. And when you run the app and check the weather, then you should get the temperature
145

146
00:14:12,790 --> 00:14:20,130
back in a string format with only a single number after the decimal place.
146

147
00:14:20,350 --> 00:14:26,920
So pause the video and see if you can complete this challenge.
147

148
00:14:27,310 --> 00:14:27,610
All right.
148

149
00:14:27,640 --> 00:14:30,970
So we've got a temperatureString computed property here.
149

150
00:14:32,140 --> 00:14:38,650
And remember, we always have to provide a data type for the computed property, and then we open a set
150

151
00:14:38,650 --> 00:14:42,280
of curly braces and actually work out what it should be.
151

152
00:14:42,280 --> 00:14:49,370
So in this case, I'm going to return a String with the format of a single decimal place,
152

153
00:14:49,540 --> 00:14:57,550
so thats's "%.1f" and then I'm gonna pass in my temperature which is this Double right
153

154
00:14:57,550 --> 00:15:06,030
here as the property that's going to be formatted to this particular format. And now when you run your
154

155
00:15:06,030 --> 00:15:12,960
app, you should be able to see that whatever temperature you get back will be printed with only one decimal
155

156
00:15:12,960 --> 00:15:20,940
place. And this temperature string now has the data type of a String ready for us to put into our temperature
156

157
00:15:20,940 --> 00:15:22,570
label.
157

158
00:15:22,680 --> 00:15:28,980
So in the next lesson, we're going to tie it all together and get our weather app working with all of
158

159
00:15:28,980 --> 00:15:33,750
these different components together. For all of that and more, I'll see you there.
