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.