0 1 00:00:00,630 --> 00:00:05,820 In the last lesson, we wrote the networking logic for our app, and we were wondering how to show our results 1 2 00:00:05,850 --> 00:00:07,020 on the screen. 2 3 00:00:07,020 --> 00:00:12,120 How can we pass the results from our network manager to the List inside the ContentView? 3 4 00:00:12,900 --> 00:00:21,840 Well, the simplest way of doing this is by making our NetworkManager conform to a protocol called 4 5 00:00:21,900 --> 00:00:23,170 ObservableObject. 5 6 00:00:23,190 --> 00:00:31,440 And this means that it can actually start to broadcast one or many of its properties to any interested 6 7 00:00:31,440 --> 00:00:32,500 parties. 7 8 00:00:32,610 --> 00:00:43,350 So let's create a property code posts and initialize it as a new array of Post objects. 8 9 00:00:43,860 --> 00:00:53,520 And once our networking completes and we get hold of the data from the API inside our constant code Results, 9 10 00:00:53,860 --> 00:01:00,140 well then we can set our posts to equal the results.hits. 10 11 00:01:00,240 --> 00:01:10,380 And notice how hits is, of course, an array of Post objects which matches perfectly with all 11 12 00:01:10,680 --> 00:01:12,870 variable code posts. 12 13 00:01:12,870 --> 00:01:20,670 The only thing we have to do is to change the posts to add the self.posts because we're inside 13 14 00:01:20,670 --> 00:01:28,510 a closure. So, now that we've got this posts which stores all of the results hits, 14 15 00:01:28,530 --> 00:01:32,640 so essentially this array here of all the Post objects, 15 16 00:01:32,640 --> 00:01:39,210 the next thing to do is to actually publish our posts to any interested parties. 16 17 00:01:39,270 --> 00:01:47,070 We do that using a property wrapper code @Published. So, it's kind of like your RSS feeds if you will. 17 18 00:01:47,070 --> 00:01:53,070 If you subscribe to this property code posts, then you'll be able to hear from it whenever the contents 18 19 00:01:53,070 --> 00:02:02,450 change. And in order to listen to it in our ContentView, we're going to create a object from that 19 20 00:02:02,460 --> 00:02:03,900 Network Manager class. 20 21 00:02:03,900 --> 00:02:11,820 So it's going to be called networkManager and it's going to be initialized from NetworkManager, 21 22 00:02:11,820 --> 00:02:17,910 and then I'm just going to add the parentheses to initialize that. And this NetworkManager is going to be 22 23 00:02:17,910 --> 00:02:23,040 marked with a property wrapper code @ObservedObject. 23 24 00:02:23,040 --> 00:02:28,590 So notice how there is a ObservableObject which is the protocol here, 24 25 00:02:28,710 --> 00:02:35,760 so it makes the NetworkManager observable. And then one or many of its properties can be published 25 26 00:02:35,760 --> 00:02:43,110 to say that whenever it has changes to notify all of the listeners. And to set up a property as a listener, 26 27 00:02:43,530 --> 00:02:46,760 we add the @ObservedObject property wrapper. 27 28 00:02:46,770 --> 00:02:50,900 In this way, we're subscribing to the updates from the NetworkManager. 28 29 00:02:51,030 --> 00:02:54,320 So, now whenever the networkManager updates, 29 30 00:02:54,480 --> 00:03:02,760 this is going to trigger. And we can use the networkManager.posts properties to update our list. 30 31 00:03:02,760 --> 00:03:09,570 So inside here, instead of using the posts which comes from this static list which are common out, 31 32 00:03:09,570 --> 00:03:20,800 we're going to be using the networkManager.posts. And that is, of course, our published property right here. 32 33 00:03:21,330 --> 00:03:28,710 So whenever post changes, then it's going to trigger a rebuild of our list updating everything that's 33 34 00:03:28,710 --> 00:03:30,060 inside. 34 35 00:03:30,060 --> 00:03:32,950 Now, notice there's just one thing missing. 35 36 00:03:32,970 --> 00:03:36,290 No where do we actually call this fetchData. 36 37 00:03:36,660 --> 00:03:42,330 So where can we do that in our SwiftUI ContentView? 37 38 00:03:42,330 --> 00:03:48,910 Well, with every ContentView, there is a method called onAppear. 38 39 00:03:50,640 --> 00:03:57,840 And this onAppear is almost like our viewDidLoad that we've gotten used to in our UIKit world. 39 40 00:03:57,840 --> 00:04:06,120 So if we call this onAppear method with a perform property, then we can pass a function in here that 40 41 00:04:06,120 --> 00:04:13,000 will be performed when this body view appears on the screen. 41 42 00:04:13,170 --> 00:04:21,870 So in this case, the perform is, again, going to be a closure, so we can select this placeholder and hit 42 43 00:04:21,990 --> 00:04:29,430 enter to turn it into a trailing closure. And inside these curly braces, we're going to get 43 44 00:04:29,430 --> 00:04:34,350 our networkManager to trigger the fetchData method. 44 45 00:04:34,710 --> 00:04:41,310 And, of course, because we're inside a closure, we have to add "self" in front. So the whole sequence of events 45 46 00:04:41,340 --> 00:04:50,970 now is our view loads up, a NavigationView with a list, and a navigation title. And as soon as it appears, 46 47 00:04:51,300 --> 00:04:59,370 we trigger the NetworkManager's fetchData method. And this will take a little while depending on the 47 48 00:04:59,370 --> 00:05:03,940 internet speed to fetch the data from 48 49 00:05:03,960 --> 00:05:05,500 the Algolia Hacker News API. 49 50 00:05:05,820 --> 00:05:10,090 And once we get the data back, we decode the data. 50 51 00:05:10,200 --> 00:05:12,900 If there were any errors, then we captured and imprinted. 51 52 00:05:13,140 --> 00:05:20,130 But if there were no errors, then we go ahead and save the results.hits which contains an array of 52 53 00:05:20,130 --> 00:05:29,100 post objects to all Posts property here. And because this post property is published, it means that anybody 53 54 00:05:29,100 --> 00:05:37,230 who is subscribed to the observed object, so the network manager will have the post property updated 54 55 00:05:37,230 --> 00:05:41,520 in real time, and the UI will update accordingly. 55 56 00:05:41,520 --> 00:05:48,420 Now, there's just one last thing that we have to do which is the point when we use @Published, 56 57 00:05:48,420 --> 00:05:54,510 we always have to make sure that we fetch the main thread. So we have to tap into the dispatchQueue 57 58 00:05:55,380 --> 00:06:05,130 and we're going to tap into .main.async. And inside this closure, we're going to set the published 58 59 00:06:05,130 --> 00:06:06,400 property. 59 60 00:06:06,510 --> 00:06:14,310 So if you don't, you'll get an error in the console. But, effectively, it's because this property is a property 60 61 00:06:14,340 --> 00:06:20,300 that other objects are listening to. This update for it must happen on the main thread. If it happens 61 62 00:06:20,320 --> 00:06:26,400 at the background, then our content view will get notified in a timely fashion. 62 63 00:06:26,520 --> 00:06:35,430 So, now all that's left to do is to go ahead and run our app and see whether if we're able to get our 63 64 00:06:35,430 --> 00:06:38,460 post title showing up from the API. 64 65 00:06:41,080 --> 00:06:47,170 And when we run our app, you can see that there are parts of our app which are working just fine, 65 66 00:06:47,170 --> 00:06:53,150 but our list is not rendering and the error that we're getting is something called valueNotFound. 66 67 00:06:53,330 --> 00:06:59,330 It's telling us that our URL property seems to have a value of nil, 67 68 00:06:59,470 --> 00:07:04,430 so we expect it to have a string value but found null instead. 68 69 00:07:04,450 --> 00:07:05,640 So what's going on here? 69 70 00:07:07,420 --> 00:07:15,490 If we take a look at the data that's being rendered from the results of the API call, you can see that 70 71 00:07:15,510 --> 00:07:24,070 the URL property tends to have a string value. But there are certain cases, especially the 71 72 00:07:24,070 --> 00:07:28,770 Ask Hacker News posts where there is actually no URL at all. 72 73 00:07:28,870 --> 00:07:35,560 It's just a text post with a question and a whole bunch of comments and answers. 73 74 00:07:35,560 --> 00:07:44,320 So in this case, because URL is null, our decoder actually fails and we catch the error by printing 74 75 00:07:44,320 --> 00:07:45,490 it out. 75 76 00:07:45,580 --> 00:07:47,130 So what can we do? 76 77 00:07:47,140 --> 00:07:55,000 Well, we can change our URL to an optional string to allow it to be null in certain cases. 77 78 00:07:55,000 --> 00:07:57,220 And now if you rerun the app, 78 79 00:08:02,470 --> 00:08:10,600 you'll see that our list is now being rendered and we're getting all of the titles that are from our 79 80 00:08:10,600 --> 00:08:13,120 live API data. 80 81 00:08:13,120 --> 00:08:19,470 So let's jazz up our list a little bit. Instead of just having a single piece of text, 81 82 00:08:19,570 --> 00:08:25,930 why don't we add our post title as well as the number of points the post received, 82 83 00:08:25,930 --> 00:08:31,530 so the number of upvotes, and we can nest this inside a HStack. 83 84 00:08:33,350 --> 00:08:41,870 The first thing that we're going to show is the number of points. So we can either turn it into a string 84 85 00:08:41,870 --> 00:08:48,340 by using the string initializer, and then tapping into post.points. 85 86 00:08:48,350 --> 00:08:53,570 Alternatively, you can also use string interpolation, but both ways work the same. 86 87 00:08:53,720 --> 00:08:59,540 So let's run our app again and see if we can get the points property rendered on screen. 87 88 00:09:01,930 --> 00:09:02,770 So there we go. 88 89 00:09:02,770 --> 00:09:09,910 We've got our points now showing up on the left, our titles showing up in the middle, and each cell in 89 90 00:09:09,910 --> 00:09:15,110 the list is being adjusted to be able to show all of the text. 90 91 00:09:15,220 --> 00:09:19,670 So that's pretty neat. And you could stop here if you wish. 91 92 00:09:19,780 --> 00:09:28,120 But what if we wanted to be able to show each of the links inside our Hacker News app? And that's exactly 92 93 00:09:28,120 --> 00:09:30,750 what we'll do in the next lesson. In the next lesson, 93 94 00:09:30,760 --> 00:09:36,460 we'll add the finishing touches to our app by making the links open up inside a web view from within 94 95 00:09:36,460 --> 00:09:37,500 our app. 95 96 00:09:37,540 --> 00:09:44,020 Also we'll handle the navigation between the list of Hacker News items and those web views. For all of that 96 97 00:09:44,320 --> 00:09:44,830 and more, 97 98 00:09:44,860 --> 00:09:46,110 I'll see you in the next lesson.