Day 33 - 100 Days of Swift

3 minute read

Project 7 (part 1)

Day 33 is the first part of the seventh project. This project is to build an app that lets you browse petitions that have been made to the Whitehouse. Today, you get the project set up, add a custom struct to hold the data and allow for parsing the JSON, and make a simple call to get some results and display them on screen.

First, you set up a new project. You swap out a table view controller for the default view controller, and embed it in a navigation controller, and embed that in a tab bar controller. This is because later in the project, we will have one tab for recent petitions and another for popular petitions. After that, you add the necessary UITableViewDataSource methods to ViewController:

1
2
3
4
5
6
7
8
9
10
11
12
var petitions: [String] = []

override func tableView(_ tableView: UITableView,
                        cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",
                                             for: indexPath)

    cell.textLabel?.text = "Petition title"
    cell.detailTextLabel?.text = "Petition body"

    return cell
}

Next, you add a custom Petition struct to hold the data that we care about getting back from the API. You make it conform to Codable so that we can use it with a JSONDecoder:

1
2
3
4
5
struct Petition: Codable {
    var title: String
    var body: String
    var signatureCount: Int
}

Because of the way the JSON that we will be receiving is structured, we also need a custom struct to hold an array of petitions:

1
2
3
struct Petitions: Codable {
    var results: [Petition]
}

Now that we have those we can make a few changes to ViewController:

1
2
3
4
5
6
7
var petitions: [Petition] = []

// In tableview(_:cellForRowAt:)
let petition = petitions[indexPath.row]

cell.textLabel?.text = petition.title
cell.detailTextLabel?.text = petition.body

And then we can add some helper functions to actually load some petitions. It’s not really ideal to load these on the main thread like this, but he says we’re doing it that way for simplicity’s sake right now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private func loadPetitions() {
    let urlString = "https://api.whitehouse.gov/v1/petitions.json?limit=100"

    if let url = URL(string: urlString),
        let data = try? Data(contentsOf: url) {
        parse(json: data)
    }
}

private func parse(json: Data) {
    let decoder = JSONDecoder()

    if let jsonPetitions = try? decoder.decode(Petitions.self, from: json) {
        petitions = jsonPetitions.results
        tableView.reloadData()
    }
}

Then we just call loadPetitions in viewDidLoad and we get a nice long list of Whitehouse petitions in our tableview:

1
2
3
4
5
override func viewDidLoad() {
    super.viewDidLoad()

    loadPetitions()
}

Here’s what it looks like so far:

Screenshot of working app.

You can find my version of this project at the end of day 33 on Github here.

Reflections

I think today was a great example of the power behind Codable. I know a lot of people don’t care for it, or think it is too limited or whatever. But it makes it really easy to get something setup and running really fast and without much work. I think it is great for people who are learning. It’s amazing how awesome it feels knowing that your app can just consume and display whatever information is available out there on the internet. That’s a big step. I also think it is great for prototyping, or just trying API’s out to see if they’ll do what you need them to. You have to write so little and everything “just works”, it’s great for moving fast and testing.