0
1
00:00:01,010 --> 00:00:09,770
So in the last lesson, we talked about the OpenWeather Map API and how we can use it by simply passing
1

2
00:00:09,770 --> 00:00:13,640
over the queries that we're interested in.
2

3
00:00:13,640 --> 00:00:22,160
For example, we formatted our final URL that queries the API for the weather in Paris. And we managed
3

4
00:00:22,160 --> 00:00:29,030
to get hold of that by putting it simply into the browser and getting the browser to fetch this data
4

5
00:00:29,030 --> 00:00:30,100
back.
5

6
00:00:30,140 --> 00:00:35,270
Now, this process in programming, we would call Networking.
6

7
00:00:35,270 --> 00:00:38,830
It's not like going to a room and exchanging business cards.
7

8
00:00:39,050 --> 00:00:43,320
Instead, your app is talking to a web server.
8

9
00:00:43,790 --> 00:00:47,240
And in our case, it's OpenWeather Map's web server.
9

10
00:00:47,240 --> 00:00:52,040
So the web server is like an application in itself.
10

11
00:00:52,040 --> 00:01:01,250
And what we're trying to do is to talk to the web server of OpenWeather Map and make a request for
11

12
00:01:01,250 --> 00:01:10,100
data. And as a part of this request, we pass over some of the queries for what data we're interested in,
12

13
00:01:10,100 --> 00:01:18,230
for example, the name of the city for whose whether we want to get back. Now, when the web server looks at
13

14
00:01:18,230 --> 00:01:24,710
your query, as long as it can recognize it because you've been abiding by the rules of the API, say, you're
14

15
00:01:24,710 --> 00:01:31,790
using that letter q which is lowercase, and you're passing over an app ID and you've actually got a
15

16
00:01:31,790 --> 00:01:40,070
valid app ID, well, then the web server is going to respond back to your app and it's going to send
16

17
00:01:40,070 --> 00:01:49,270
back the data that you requested. This entire process is called networking. And in Swift, when we want
17

18
00:01:49,270 --> 00:01:55,630
to perform that networking action, just like what you saw in the browser using Chrome,
18

19
00:01:55,630 --> 00:01:58,230
there's a couple of steps that we have to go through.
19

20
00:01:58,270 --> 00:02:06,490
First, we have to create an actual URL object, and then we create what's called a URL session which
20

21
00:02:06,490 --> 00:02:12,010
is going to be the object that's going to be doing on networking, effectively, like what the browser is
21

22
00:02:12,010 --> 00:02:13,090
doing.
22

23
00:02:13,180 --> 00:02:20,590
Step three: we give this you URL session a task, just like how we put the URL into the browser's
23

24
00:02:20,590 --> 00:02:29,900
URL bar, and gave our browser a task to do which is fetching the data from that particular source.
24

25
00:02:29,920 --> 00:02:36,490
The final step is to actually start the task. And that's effectively when we hit enter in the search
25

26
00:02:36,490 --> 00:02:44,040
bar which triggers the entire networking process and, hopefully, we get our data back.
26

27
00:02:44,110 --> 00:02:50,410
So let's try doing this in our project. In our WeatherManager,
27

28
00:02:50,640 --> 00:02:56,130
I'm gonna create another method, and this is going to be called performRequest.
28

29
00:02:56,400 --> 00:03:03,900
Now, the request is going to be based on the URL string that we got which is, of course, going to be
29

30
00:03:03,930 --> 00:03:06,060
a string data type.
30

31
00:03:06,060 --> 00:03:13,810
Then we can, instead of printing the URL string, we can call performRequest and pass over this URL
31

32
00:03:13,860 --> 00:03:23,180
string which now lands in here as the inputs and we can access it through this URL string. And inside
32

33
00:03:23,240 --> 00:03:30,350
our performRequest method is where we're going to carry out those four steps of networking.
33

34
00:03:30,350 --> 00:03:33,350
Step one is to create a URL.
34

35
00:03:33,590 --> 00:03:40,080
So let's create a URL. And we do that by using URL initializer.
35

36
00:03:40,490 --> 00:03:44,510
So this is going to be a structure that we're going to create.
36

37
00:03:44,510 --> 00:03:50,950
And as always, we initialize our structures and classes with a set of parenthesis.
37

38
00:03:51,110 --> 00:03:58,070
And now if we scroll through this list of different initializers, you'll come across one which takes
38

39
00:03:58,160 --> 00:04:05,400
a string. And that's what we've got, we've got a string to represent the URL. And in this initializer,
39

40
00:04:05,570 --> 00:04:11,720
we have to pass in our string which is the URL string that we got as the input.
40

41
00:04:11,750 --> 00:04:18,280
Now, notice how this way of initializing URLs from strings which commonly can have typos,
41

42
00:04:18,280 --> 00:04:22,250
say, we misspelled "q" and instead wrote "p" by accident,
42

43
00:04:22,250 --> 00:04:24,110
well, then it might fail.
43

44
00:04:24,110 --> 00:04:32,290
So that's why this initializer creates an optional URL. And you can actually see that even at the point
44

45
00:04:32,290 --> 00:04:39,430
when we were choosing from our Xcode autosuggest list, you can see that it creates a optional URL,
45

46
00:04:39,460 --> 00:04:47,200
URL with the question mark here. So in order to use our URL that's created this way,
46

47
00:04:47,290 --> 00:04:52,020
we're going to use "if let." So we optionally bind the
47

48
00:04:52,030 --> 00:04:55,380
URL that's created to a constant code URL
48

49
00:04:55,660 --> 00:05:04,470
as long as this doesn't fail and doesn't end up being nil. So now that we've got our URL created,
49

50
00:05:04,470 --> 00:05:08,100
it's time to move on to the next step.
50

51
00:05:08,340 --> 00:05:17,010
Step two is to create a URL session. And, again, pretty easy, we create a "let" constant which we'll call
51

52
00:05:17,010 --> 00:05:25,700
session and we're going to set this to a URL session object. So it's not a session task, it's actually
52

53
00:05:25,700 --> 00:05:33,400
just a session. And as soon as I open my set of parentheses, you can see that there's two ways of creating
53

54
00:05:33,440 --> 00:05:41,120
a URL session, one with lots of different options, and another one which where we just have a single
54

55
00:05:41,150 --> 00:05:47,660
configuration property we have to set. The configuration that we're going to use is going to be just
55

56
00:05:47,720 --> 00:05:55,910
the default configuration. This ends up creating our URL session object which is effectively like
56

57
00:05:55,970 --> 00:06:04,810
browser. It's the thing that can perform the networking. Now, we can move on to step three
57

58
00:06:04,810 --> 00:06:11,800
which is to give the session a task. So we can tap into our session that we've just created and we can give
58

59
00:06:11,800 --> 00:06:16,600
it a data task with URL and completion handler.
59

60
00:06:16,780 --> 00:06:19,080
So this is the one that you want to choose.
60

61
00:06:19,300 --> 00:06:27,190
Creates a task that retrieves the contents of the specified URL and then calls a handler or a method
61

62
00:06:27,190 --> 00:06:33,430
once it completes. So let's hit enter and let's create that line of code.
62

63
00:06:33,430 --> 00:06:38,130
Now, the URL is, of course, going to be the URL that we created just now.
63

64
00:06:38,170 --> 00:06:41,680
So that's this one right here.
64

65
00:06:42,070 --> 00:06:43,830
And the completionHandler,
65

66
00:06:43,870 --> 00:06:46,210
we're going to leave for the moment.
66

67
00:06:46,270 --> 00:06:54,000
We're going to proceed forward and finish the last step which is to start the task.
67

68
00:06:54,040 --> 00:07:05,520
Now, this method returns a URLSession dataTask. So we can set the output as a constant code task.
68

69
00:07:05,620 --> 00:07:14,260
So now we create a dataTask with our URL, and then we set it equal to this constant task. And in step
69

70
00:07:14,260 --> 00:07:18,300
four, we can say task.resume.
70

71
00:07:18,400 --> 00:07:21,180
Now, the naming of this method is a little bit weird.
71

72
00:07:21,190 --> 00:07:22,660
Why is it not called start?
72

73
00:07:22,660 --> 00:07:23,960
Why is it called resume?
73

74
00:07:25,000 --> 00:07:33,040
Well, in the case of tasks, because they can be suspended, and in fact, the newly initialized tasks, just
74

75
00:07:33,040 --> 00:07:39,120
like what we've done here, where we've created a new task they begin in a suspended state.
75

76
00:07:39,220 --> 00:07:43,350
So you need to call this method to start the task, basically.
76

77
00:07:43,450 --> 00:07:49,120
So all of this goodness is coming from documentation reading, as usual.
77

78
00:07:49,180 --> 00:07:53,690
So now let's address our completionHandler.
78

79
00:07:53,690 --> 00:07:56,390
What exactly is a completionHandler?
79

80
00:07:57,110 --> 00:08:03,270
Well, in programming, there's a lot of cases where you have very time-consuming tasks.
80

81
00:08:03,500 --> 00:08:12,410
And for example, in this case, when we create our task and we start the task, what this task is doing is
81

82
00:08:12,770 --> 00:08:21,050
it's effectively having to go to this URL, grab the data, go across the entire world, and come back
82

83
00:08:21,140 --> 00:08:27,350
with the data. That can take anywhere between a fraction of a second to a couple of minutes depending
83

84
00:08:27,350 --> 00:08:29,840
on your internet connection speed.
84

85
00:08:29,840 --> 00:08:32,920
Therefore, we can't just wait for it,
85

86
00:08:32,930 --> 00:08:33,320
right?
86

87
00:08:33,380 --> 00:08:35,780
Our app needs to do other things.
87

88
00:08:35,780 --> 00:08:43,850
So instead, we have a completionHandler, which even though it looks like an input parameter, it actually
88

89
00:08:43,940 --> 00:08:47,450
takes a function as the value.
89

90
00:08:47,450 --> 00:08:53,570
And you can see that it's a function because it's got the classic things that a function has, the parenthesis
90

91
00:08:53,570 --> 00:09:00,950
for the inputs, and then a hyphen, an angle bracket for the output. Even though, in this case, the output
91

92
00:09:01,010 --> 00:09:04,060
is void, which means there's actually no output,
92

93
00:09:04,220 --> 00:09:11,150
it's just a method like this method which doesn't actually have any outputs. But to represent and to
93

94
00:09:11,150 --> 00:09:14,050
show us that this is definitely a function,
94

95
00:09:14,300 --> 00:09:18,680
that's why it has the hyphen angle bracket void.
95

96
00:09:18,680 --> 00:09:24,190
Effectively, what it's saying is that it needs to take a function as the input.
96

97
00:09:24,290 --> 00:09:25,570
So let's give it a function.
97

98
00:09:25,580 --> 00:09:28,130
Let's create a function somewhere down here.
98

99
00:09:28,820 --> 00:09:36,410
So just before the last closing bracket, I'm going to create a function called handle. and this handle
99

100
00:09:36,410 --> 00:09:43,430
method is going to take all of the inputs that are prescribed right here. You can see there's the first
100

101
00:09:43,430 --> 00:09:47,110
input which needs to be of date type optional data,
101

102
00:09:47,240 --> 00:09:52,780
then another one which is optional URLResponse, and then another one which is an optional error.
102

103
00:09:52,850 --> 00:09:54,840
A lot of optionals, basically.
103

104
00:09:54,890 --> 00:10:03,440
So let's go ahead and add our data property which is of type Data optional, and then our response parameter
104

105
00:10:03,770 --> 00:10:07,940
which is of data type URLResponse optional,
105

106
00:10:08,330 --> 00:10:14,090
and finally, our error which is going to be of type Error optional.
106

107
00:10:14,090 --> 00:10:21,170
So here's our method. And if we wanted to signify that, it's not going to return anything, then we can
107

108
00:10:21,170 --> 00:10:24,200
actually have the return void here as well.
108

109
00:10:24,200 --> 00:10:28,600
But this actually does nothing when we're just defining a method, that doesn't return anything.
109

110
00:10:28,700 --> 00:10:30,900
We can also just actually not mention it.
110

111
00:10:30,920 --> 00:10:37,160
It does the same thing. Now, that we've got our function defined, we can actually pass it in here.
111

112
00:10:37,160 --> 00:10:43,610
So as soon as I start writing handle, you can see that Xcode has recognize this as a method,
112

113
00:10:43,610 --> 00:10:52,640
and if I hit enter, it'll insert it in as the value of this completionHandler input. And if I hit command B
113

114
00:10:52,700 --> 00:11:00,410
to build and hit my app with a stick, then you can see that Xcode is completely happy with what I've
114

115
00:11:00,410 --> 00:11:03,440
done here,even though it looks a little bit weird.
115

116
00:11:03,860 --> 00:11:06,110
So let's break it down here.
116

117
00:11:06,320 --> 00:11:14,300
Effectively, what I'm doing is I'm passing in a call to the method handle which I created here.
117

118
00:11:14,300 --> 00:11:20,560
And for each of these inputs, I'm actually not passing in any values.
118

119
00:11:20,630 --> 00:11:27,260
Instead, the completionHandler is going to be triggered by the task.
119

120
00:11:27,260 --> 00:11:36,800
So when this session completes its networking and the task is complete, it is the one that will call
120

121
00:11:36,890 --> 00:11:45,680
the completionHandler. And you can have a read of it by option clicking on the completionHandler.
121

122
00:11:45,770 --> 00:11:50,910
And this handler when it gets called, it's going to pass in those three things
122

123
00:11:50,930 --> 00:11:59,120
as long as it has them, an optional piece of data, an optional response, and an optional error. So effectively,
123

124
00:11:59,450 --> 00:12:04,760
we're leaving it to the task to trigger this method.
124

125
00:12:04,760 --> 00:12:12,790
But once it does, then we'll have access to the data response an error object that it sends us.
125

126
00:12:12,920 --> 00:12:20,740
So now inside our handle method, we could, for example, check to see was there an error in this whole networking
126

127
00:12:20,740 --> 00:12:21,650
process.
127

128
00:12:21,850 --> 00:12:29,410
So if error does not equal nil, well, in that case, why don't we go ahead and print the error.
128

129
00:12:30,310 --> 00:12:36,490
And because it's an optional, it needs to be unwrapped if we want to use it.
129

130
00:12:36,550 --> 00:12:39,910
And in this case, because we've already checked that it's not nil,
130

131
00:12:39,910 --> 00:12:43,880
this will now be able to let us check for errors.
131

132
00:12:43,880 --> 00:12:49,360
Now, what we want to do if there was an error is we want to simply return.
132

133
00:12:49,360 --> 00:12:56,140
Now, notice how there's nothing after the return keyword. When I simply just add the word "return," it means
133

134
00:12:56,590 --> 00:13:05,050
exit out of this function, and don't continue. Because the next step is we want to check what data we
134

135
00:13:05,050 --> 00:13:06,220
got back.
135

136
00:13:06,220 --> 00:13:10,490
So if there was an error, then I don't want to actually do anything else.
136

137
00:13:10,570 --> 00:13:11,890
It obviously failed.
137

138
00:13:11,980 --> 00:13:16,840
So proceeding forward is probably going to create more problems for me.
138

139
00:13:17,080 --> 00:13:25,180
But if there were no errors, well, in that case, I'm going to create a "if let" constant, which I'll call
139

140
00:13:25,180 --> 00:13:33,220
safeData, which is going to use optional binding to unwrap my data object that I got back.
140

141
00:13:33,220 --> 00:13:41,920
So if let safeData = data, well, then I can take a look at this data. Now, data objects are not quite
141

142
00:13:41,980 --> 00:13:44,160
as easily printable as strings.
142

143
00:13:44,650 --> 00:13:51,650
If I simply just went ahead and printed safeData, you won't actually see the contents of the data.
143

144
00:13:51,710 --> 00:14:00,790
Let's first convert it into a string. So we can say let dataString = String data type, and we're
144

145
00:14:00,790 --> 00:14:04,570
going to initialize it using one of its initializers.
145

146
00:14:04,810 --> 00:14:12,430
And if we go down this list of all of these initializers, there's one of these that takes a data object as the
146

147
00:14:12,430 --> 00:14:13,220
input.
147

148
00:14:13,390 --> 00:14:14,510
So that's what we need.
148

149
00:14:14,530 --> 00:14:21,070
We're going to pass our safe data in here and we're going to pass it into a string. And the encoding
149

150
00:14:21,070 --> 00:14:28,600
for most of the data that we get back from the web is UTF-8 and this is just a standardized protocol
150

151
00:14:28,840 --> 00:14:37,480
for encoding text in websites. So now that we've got this as a string, we can go ahead and try to print
151

152
00:14:37,930 --> 00:14:39,470
our data string.
152

153
00:14:39,670 --> 00:14:47,520
Let's give this code a go and see if it actually works. Now let's give it a spin.
153

154
00:14:47,530 --> 00:14:53,890
I'm going to search for the weather in Paris, and then when I click search, you'll notice that we get
154

155
00:14:53,890 --> 00:15:02,500
an error in our debug. And it tells us that there's an error with a error code and the resource that
155

156
00:15:02,500 --> 00:15:10,330
you're requesting could not be loaded because App Transport Security policy requires the use of a secure
156

157
00:15:10,360 --> 00:15:11,630
connection.
157

158
00:15:11,650 --> 00:15:13,030
What does this mean?
158

159
00:15:13,030 --> 00:15:20,470
Well, notice how even back in the Chrome browser when we were requesting the data from the Open Weather
159

160
00:15:20,470 --> 00:15:26,170
Map API, we were getting this warning from Chrome as well, saying, "Hey, this URL that you're trying
160

161
00:15:26,170 --> 00:15:29,850
to access is not secure."
161

162
00:15:29,960 --> 00:15:36,800
And the reason is because when we're sending this request, anyone one who's intercepting this request
162

163
00:15:36,800 --> 00:15:44,930
can see our app ID, our units which we might not care about, and our queries. In order for this to be
163

164
00:15:45,020 --> 00:15:47,400
secured and encrypted,
164

165
00:15:47,450 --> 00:15:53,240
what we have to do is we have to have an HTTPS request.
165

166
00:15:53,480 --> 00:16:01,790
So something that looks like this. Whereas our URL that we're using at the moment is an HTTP
166

167
00:16:01,790 --> 00:16:02,590
URL.
167

168
00:16:02,780 --> 00:16:10,190
So in order to get to OpenWeather Map's API is through a secure route, then we can simply just change
168

169
00:16:10,190 --> 00:16:12,980
this to HTTPS.
169

170
00:16:13,040 --> 00:16:18,380
So this is a common error that you might come across when you're doing networking and it's really important
170

171
00:16:18,380 --> 00:16:25,160
to be aware of the fact that Apple actually catches you out if you're trying to access an HTTP or trying
171

172
00:16:25,160 --> 00:16:27,920
to load a resource in an unsafe manner.
172

173
00:16:28,670 --> 00:16:35,420
So now that we're connecting to Open Weather Map through a secure route, as soon as I go ahead and enter
173

174
00:16:35,660 --> 00:16:44,240
Paris again, as the request, you'll see down here that I'm getting my data string printed in here with
174

175
00:16:44,570 --> 00:16:52,130
the coordinates of Paris, the weather in Paris that there is a clear sky, and that the temperature is
175

176
00:16:52,190 --> 00:16:55,910
23.58 Celsius.
176

177
00:16:56,060 --> 00:17:03,130
So we've effectively done the same thing as we have done here by putting our request into the URL,
177

178
00:17:03,350 --> 00:17:12,920
but instead, this time, we're doing it using URLSession. So this way of using the completionHandler
178

179
00:17:13,610 --> 00:17:21,320
getting the task object to call this method whenever it's done getting the data off of the internet,
179

180
00:17:21,950 --> 00:17:29,480
allows us to get on with other things, and only trigger our print statement or whatever else it is that
180

181
00:17:29,480 --> 00:17:31,580
we might need to do with the string
181

182
00:17:31,580 --> 00:17:40,640
once the process has completed. So while this method works where we create a method and we pass in the
182

183
00:17:40,640 --> 00:17:48,200
method here as the input value, there's a much more common way of writing this and it involves something
183

184
00:17:48,200 --> 00:17:56,240
called closures which are effectively functions that are anonymous, functions without a name like this
184

185
00:17:56,510 --> 00:18:03,860
name here "handle." If you already know about Swift closures and you want to skip the next Deep Dive, then
185

186
00:18:03,860 --> 00:18:12,260
feel free to do so. But if you want to know how we can use closures to create the typical anonymous function,
186

187
00:18:12,620 --> 00:18:15,610
then head over to the next lesson and learn more about it there.
