0 1 00:00:00,780 --> 00:00:06,930 Now that you've learned how to display items inside a SwiftUI list view and work with the identifiable 1 2 00:00:06,930 --> 00:00:07,910 protocol, 2 3 00:00:07,920 --> 00:00:14,490 let's get our app ready to do some networking. Our networking code will use the URL session and decode 3 4 00:00:14,550 --> 00:00:20,910 a JSON response using the JSON decoder, similar to what we've already done in the CLIMA and the bitcoin 4 5 00:00:20,910 --> 00:00:21,840 modules. 5 6 00:00:21,840 --> 00:00:25,980 But let's see how this will work in a project built with SwiftUI. 6 7 00:00:25,980 --> 00:00:29,070 So inside our H4X0R News app, 7 8 00:00:29,100 --> 00:00:37,170 I'm going to create a new group called Models. And inside this folder of Models, I'm going to right-click 8 9 00:00:37,920 --> 00:00:45,990 and create a new file which is going to be a Swift File, and I'm going to call it MetworkManager. 9 10 00:00:48,530 --> 00:00:49,670 Inside this file, 10 11 00:00:49,670 --> 00:00:55,940 I'm going to create a new class called NetworkManager, and then I'm going to open up a set of curly 11 12 00:00:55,940 --> 00:00:57,190 braces. 12 13 00:00:57,290 --> 00:01:08,450 This network manager is going to have a method called fetchData. It doesn't take any inputs, but it does 13 14 00:01:08,510 --> 00:01:10,240 do quite a few things. 14 15 00:01:10,280 --> 00:01:15,940 So the first thing it's going to do is to create a URL from a string. 15 16 00:01:15,980 --> 00:01:19,050 So we're going gonna do the same as we did in Clima. 16 17 00:01:19,130 --> 00:01:21,980 We're going to create it from the URL initializer 17 18 00:01:22,070 --> 00:01:29,300 and we're going to use the one that takes a string to create the URL. So the string in this case is 18 19 00:01:29,300 --> 00:01:33,180 going to be from our Hacker News API. 19 20 00:01:33,350 --> 00:01:39,440 And if you read through the documentation on this page: hn.algolia.com/api, 20 21 00:01:39,440 --> 00:01:47,570 you can see that we can get hold of all the stories that are on the front page by using this particular 21 22 00:01:47,600 --> 00:01:48,680 query. 22 23 00:01:48,680 --> 00:01:55,190 So this is going to be the URL that I'm going to copy. And firstly, I'm going to test it in my browser 23 24 00:01:55,220 --> 00:02:02,330 just to make sure that I actually get data back. And notice how I've got the JSON Awesome again activated. 24 25 00:02:02,360 --> 00:02:08,870 So we already looked at this in the JSON lesson. But it means that I can take a look at the structure 25 26 00:02:08,960 --> 00:02:13,550 of the results that we would get back from this request. 26 27 00:02:13,550 --> 00:02:18,760 So you can see that we get an array of 20 items which is stored under something called hits. 27 28 00:02:18,950 --> 00:02:25,700 And for each item, we get a whole bunch of details about each story in Hacker News including the number 28 29 00:02:25,700 --> 00:02:30,920 of points, the title, and the URL, et cetera. 29 30 00:02:30,980 --> 00:02:38,850 So this URL seems to be working, so let's copy it, and paste it into here as the string of the URL 30 31 00:02:38,860 --> 00:02:41,050 that we're going to make the request to. 31 32 00:02:41,140 --> 00:02:47,800 But, of course, because this initialize creates an optional, let's go ahead and wrap this inside 32 33 00:02:47,850 --> 00:02:48,860 an "if let." 33 34 00:02:48,880 --> 00:02:55,840 So if we are able to generate a URL from this string, which I'm pretty confident that it can, then 34 35 00:02:55,900 --> 00:03:03,880 we're going to create a session object from the URLSession class and we're going to initialize it 35 36 00:03:03,970 --> 00:03:07,420 using a default configuration. 36 37 00:03:07,420 --> 00:03:14,440 Next, we're going to create a task which is going to be set to session.data task and we're going 37 38 00:03:14,440 --> 00:03:16,240 to choose the initializer 38 39 00:03:16,270 --> 00:03:23,200 that takes a URL and has a completionHandler with the data that we get back the Response and the 39 40 00:03:23,290 --> 00:03:24,220 Error. 40 41 00:03:24,280 --> 00:03:29,500 So the URL that we're going to be using to make this request is, of course, the URL that we 41 42 00:03:29,500 --> 00:03:36,520 generated up here. And then in the completionHandler, I'm just going to select it and hit enter, so that 42 43 00:03:36,580 --> 00:03:43,820 it splits it into a trailing closure format. So the Data is going to be called data, Response is going 43 44 00:03:43,820 --> 00:03:48,220 to be called response, and Error is going to be code error. 44 45 00:03:49,360 --> 00:03:55,840 So, now inside this closure, I'm going to check to see that if error equals nil. 45 46 00:03:55,840 --> 00:03:57,900 So there were no errors. 46 47 00:03:57,940 --> 00:04:04,360 Make sure that you don't check that it's "if error does not equal nil" which you might be tempted to. 47 48 00:04:04,360 --> 00:04:08,030 If there were no errors, then we can assume that we did get some data back. 48 49 00:04:08,170 --> 00:04:11,500 And, of course, the data we get back is in a JSON format. 49 50 00:04:11,560 --> 00:04:15,160 So we have to figure out how to refactor it. 50 51 00:04:15,190 --> 00:04:23,070 So, first, we're going to create a decoder which is created from the JSON decoder. And then we're going 51 52 00:04:23,070 --> 00:04:31,960 to try and get our JSON decoder to decode the data that we get back from our networking session. 52 53 00:04:31,960 --> 00:04:37,960 In order to do that, though, we first have to create a structure to represent all the properties that we 53 54 00:04:37,960 --> 00:04:40,600 want out of this result. 54 55 00:04:40,600 --> 00:04:47,290 So, again, inside the Models folder, we're going to create a New File and this file is going to be a Swift File 55 56 00:04:47,290 --> 00:04:58,630 which is going to be called our PostData. And here I'm going to create a struct called Results which 56 57 00:04:58,630 --> 00:05:05,020 is going to, of course, conform to the decodable protocol so that we can actually use the JSON decoder 57 58 00:05:05,410 --> 00:05:15,910 to decode our JSON data into a Result struct. And the Result struct is going to only have a single property 58 59 00:05:16,300 --> 00:05:18,160 and that's going to be "hits." 59 60 00:05:18,610 --> 00:05:20,590 Let's create a hits property. 60 61 00:05:20,710 --> 00:05:25,840 So make sure that you spell it exactly the same as you see in the response 61 62 00:05:25,840 --> 00:05:26,540 JSON. 62 63 00:05:26,920 --> 00:05:36,310 So H-I-T-S. And the hits is going to have the data format of an array of Post objects. 63 64 00:05:36,460 --> 00:05:39,130 So at the moment, it doesn't know what a post is, 64 65 00:05:39,130 --> 00:05:42,040 so let's define our Post object. 65 66 00:05:42,340 --> 00:05:50,560 Now, our Post object, again, has to conform to the decodable protocol and the properties that were interested 66 67 00:05:50,680 --> 00:05:58,690 in each of these posts is going to be the title, the number of points that the story got, 67 68 00:05:58,690 --> 00:06:02,510 so how many people upvoted it, as well as the URL. 68 69 00:06:02,770 --> 00:06:05,460 So let's create some properties here. 69 70 00:06:05,500 --> 00:06:14,140 So first, I'm going to create the points which is going to be a integer, and then I'm gonna create my 70 71 00:06:14,140 --> 00:06:16,850 title which is going to be a string. 71 72 00:06:17,020 --> 00:06:21,900 And finally, I'm gonna create our URL which is also going to be a string. 72 73 00:06:24,460 --> 00:06:31,690 Now, the last thing I'm going to add to my post structure is this objectID property because this is 73 74 00:06:31,690 --> 00:06:38,540 the number that uniquely identifies each of these posts in the Hacker News database, 74 75 00:06:38,540 --> 00:06:45,070 and it's what we're going to be using as the ID to identify each post in all project as well. 75 76 00:06:45,070 --> 00:06:53,950 So let's create the objectID, so capital "I," capital "D." And if I remember correctly, it's actually a string. 76 77 00:06:53,950 --> 00:06:57,150 So it's got the quotation marks around it. 77 78 00:06:57,510 --> 00:06:57,820 All right. 78 79 00:06:57,850 --> 00:07:04,560 So we've now created our Post structure which is going to decode from that result JSON 79 80 00:07:04,550 --> 00:07:12,160 all four of these properties that we're interested in. And notice how here it says, "An invalid 80 81 00:07:12,160 --> 00:07:18,640 redeclaration of 'Post'" and that's, of course, because in our ContentView, we already created something quite 81 82 00:07:18,640 --> 00:07:19,270 similar. 82 83 00:07:19,720 --> 00:07:26,260 So remember how we created this Post structure to be able to create Post objects that we can put into 83 84 00:07:26,260 --> 00:07:28,980 an array and render on our list. 84 85 00:07:28,990 --> 00:07:32,800 Well, this is what we're going to be doing with this Post structure instead. 85 86 00:07:32,800 --> 00:07:42,390 So let's go ahead and delete this structure, and instead head back to our Post data and make 86 87 00:07:42,480 --> 00:07:45,610 this post Identifiable. 87 88 00:07:45,660 --> 00:07:52,770 Now, remember that in order for something to be identifiable, it must have a property code ID. 88 89 00:07:52,770 --> 00:08:01,710 So let's go ahead and create that ID. Now, this ID property has to have the name id. But you'll notice 89 90 00:08:01,710 --> 00:08:07,150 that we've actually already got an identifier which identifies each post. 90 91 00:08:07,170 --> 00:08:12,260 So how can we turn this id to equal to the objectID. 91 92 00:08:12,300 --> 00:08:16,320 Well, we can use our computed properties. 92 93 00:08:16,320 --> 00:08:24,600 So instead of creating a "let," we can create a "var" code id, and it's going to have a data type of String. 93 94 00:08:25,200 --> 00:08:32,730 And then after opening up a set of curly braces, we're going to return the value of ID 94 95 00:08:32,730 --> 00:08:33,960 as an objectID. 95 96 00:08:34,050 --> 00:08:39,840 So, now whenever you try to fetch the ID, it's going to look at the value of objectID and assign 96 97 00:08:39,840 --> 00:08:42,460 it to this property as well. 97 98 00:08:42,510 --> 00:08:47,580 So that works around the constraints of the identifiable protocol. 98 99 00:08:47,730 --> 00:08:55,800 And just as a reminder, we need the identifiable protocol in order to use that structure inside our list, 99 100 00:08:56,130 --> 00:09:03,070 and for the list to know how to order each item. 100 101 00:09:03,200 --> 00:09:11,330 So, now that we've created our Results and our Post, we're now ready to decode our data. 101 102 00:09:11,330 --> 00:09:18,800 So let's head back to our network manager, and then we're going to use our decoder to decode. And the 102 103 00:09:18,890 --> 00:09:28,460 type is going to be Results.self which is the data type of that Result struct that we created 103 104 00:09:28,460 --> 00:09:33,710 here. And the data that we're going to be using comes from here. 104 105 00:09:33,710 --> 00:09:39,590 But, of course, this piece of data that comes back from the networking is an optional. 105 106 00:09:39,710 --> 00:09:47,360 So let's, first, go ahead and first optionally bind it to something called safe data to reflect 106 107 00:09:47,390 --> 00:09:48,410 safeData = data. 107 108 00:09:48,860 --> 00:09:56,630 Well, in that case, we're going to be able to use safeData in here and that will allow us to work with 108 109 00:09:56,660 --> 00:09:59,720 a non-optional piece of data. 109 110 00:09:59,930 --> 00:10:05,830 So decoder.decode, this decode method, because it can throw, 110 111 00:10:06,050 --> 00:10:10,280 it means that we have to call it using the keyword "try." 111 112 00:10:10,400 --> 00:10:18,110 And if we want to catch any errors that occur during this process of trying to decode, then we should 112 113 00:10:18,500 --> 00:10:27,850 wrap that method inside a do catch block, and print any errors that occur as a result of this method. 113 114 00:10:28,260 --> 00:10:36,270 Once this data has been decoded, we can bind it to a constant code results. 114 115 00:10:36,570 --> 00:10:42,070 And now we can use our results to populate our list. 115 116 00:10:42,180 --> 00:10:48,810 But before we can do that, we must make sure that our task which you see in this warning here, 116 117 00:10:48,810 --> 00:10:57,000 we created this task but we actually never started the task. So outside of the curly braces of the task 117 118 00:10:57,120 --> 00:10:57,860 closure, 118 119 00:10:57,870 --> 00:11:05,100 so right here, we can count from the bottom three closing brackets up, we're going to say 119 120 00:11:05,220 --> 00:11:10,490 task.resume which starts off on networking task. 120 121 00:11:10,620 --> 00:11:12,630 So that should get rid of that warning. 121 122 00:11:12,630 --> 00:11:16,890 And now we can address our results. 122 123 00:11:16,890 --> 00:11:26,040 Now, how do we get our data that's in our Network Manager over to our ContentView, given that our swift 123 124 00:11:26,100 --> 00:11:35,430 UI components, or need to monitor the state of a piece of data? And we'll answer exactly this question 124 125 00:11:35,580 --> 00:11:41,940 in the next lesson where we learn an advanced state management technique that uses the observer design 125 126 00:11:41,940 --> 00:11:42,360 pattern.