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.
