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