> For the complete documentation index, see [llms.txt](https://ios-course.cornellappdev.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ios-course.cornellappdev.com/resources/archived-past-semesters/sp23/chapters/7.-networking-ii-and-codable/lecture-handout.md).

# Lecture Handout

This lecture covers the second half of networking: decoding a response from the Internet.

## Networking & Codable

Last week we talked about how to make HTTP requests to allow your app to communicate with the Internet. Today we'll talk about how to decode the responses and put them on the screen!&#x20;

### Decoding Responses from the Internet

Starting in Swift 4, there’s a protocol called `Codable` that objects, structs, and enums can conform to to make them encodable and decodable from `JSON`. Codable items can contain an enum for the coding keys of type String and CodingKey in order to decode the values from JSON.

We'll refer to the JSON response example from last lecture again today:&#x20;

```http
{
  "title": "HTTP, Networking, and JSON",
  "year_created": 2020,
  "success": true,
  "topics": [ "HTTP", "Networking", "JSON" ],
}
```

If we wanted to decode this example JSON response into a model of type `Lecture`, we could create a `Lecture` struct that conforms to `Codable` as follows:

```swift
struct Lecture: Codable {
  var title: String
  var yearCreated: Int
  var success: Bool
  var topics: [String]
}
```

Notice how the names of our variables match the fields in our JSON. This is done on purpose! With Codable, **the names of the variables are expected to exactly match the keys in the JSON response**.

### JSON Decoding

In order to decode the JSON response into the `Lecture` class, we can create an instance of  `JSONDecoder`, and then call the `decode` method to convert it from a JSON to a `Lecture` object.&#x20;

```swift
// Assume we already received the data from an Alamofire call, stored in a variable named responseData

// Create an instance of a JSONDecoder
let jsonDecoder = JSONDecoder()

// Decode the data as a Lecture (optional type)
let lecture = try? jsonDecoder.decode(Lecture.self, from: responseData)
```

**Note**: Since the decoding can throw errors, we precede the `decode` method by a `try?`, which will make the `lecture` constant an optional value. This means that `lecture` will either contain a `Lecture` item **or** it could be `nil`.

### Using Your Decoded Data: @escaping completions

Once you’ve decoded the lecture JSON as a `Lecture` item, how do you use it? Since you're downloading this JSON from the Internet, it might take forever to load, and you only want to display this information on the screen once it’s ready (and possibly use a loading indicator in the meantime as the information loads). We also don’t want our application to just stall and wait until we get a response to do something else.

This is where a **completion handler** comes in handy. A completion handler is an argument passed into whatever networking function you make.&#x20;

The completion handler will:&#x20;

1. Take in your decoded object(s)
2. Pass them to the `ViewController` (or wherever you call this networking function from)
3. Run some block of code that you write (ex: reload the view controller with the fetched data on the screen)&#x20;

Back to the `Lecture` class example from before. Suppose we want to make a function that makes the network call and returns to us the Lecture JSON decoded as a `Lecture` item. Here’s an example of what that would look like:

```swift
static func getLecture(completion: @escaping (Lecture) -> Void) {
  Alamofire.request(endpoint, method: .get).validate().responseData { response in
    switch response.result {
    case let .success(data):
      let jsonDecoder = JSONDecoder()
      
      if let lecture = try? jsonDecoder.decode(Lecture.self, from: data) {
        /* Here we're calling the completion function 
        (passed in as an argument to the network call) 
        on the lecture object we just decoded */
        completion(lecture)
      }
    case .failure(let error):
      print(error.localizedDescription)
    }
  }
}
```

This completion handler is marked as `@escaping` because it can "escape" from the networking function call itself and hand it off to whoever called the function -- it doesn’t need to go through every line inside the function. Don't worry too much about what this means though! &#x20;

Here, you can see that `completion` is a function that takes in one argument which is of type `Lecture` and has a return type of `Void`. We only call completion when we know that the response succeeded and we actually have an actual `Lecture` object.

**Also note that here, we are using the `responseData` method instead of the `responseJSON` method!** This is important because `responseData` converts the response into a `Data` object which is what `JSONDecoder` needs to decode it.

### Making Network Calls

It's good practice to create a `NetworkManager` class with static methods for every network call your app makes, with the endpoint URLs hidden to the public (in case it’s private information!). This means that the earlier `getLecture` function in the previous code snippet would be inside a class named `NetworkManager`.&#x20;

Then, in your ViewController (or wherever you want to make a network call from), you can make a network request and handle it appropriately. For example, if you have a variable for lecture and need to reload the data of a table view after you get lecture data from the Internet, you would do it like so:

```swift
// In a view controller that has a lecture variable and tableView variable
func getClasses() {
  // Call the getLecture method in your NetworkManager
  NetworkManager.getLecture { lecture in
    self.lecture = lecture
    
    // We want to run any UI updates inside a DispatchQueue.main.async {...} block
    DispatchQueue.main.async {
      self.tableView.reloadData()
    }
  }
}
```

The `{ lecture in ... }` is the escaping completion we defined in the `NetworkManager` earlier. In this case, we get the `lecture` variable only if we made the network call to the endpoint, received a success, received the JSON, and then decoded it. If (and only if) the network call succeeded, we run completion (the block of code from lines 5 through 10). This ensures that we receive the updated Lecture object only when it’s ready, so the screen isn’t frozen while the app is trying to execute all of these network request steps.

## PDF Download

{% file src="/files/-M-DWXCZQh6DTSt9rCh7" %}
Networking II & Codable
{% endfile %}
