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.
