Skip to content

Latest commit

 

History

History

day-034

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Day 34: Project 7: Whitehouse Petitions, Part Two

Follow along at https://www.hackingwithswift.com/100/34.

📒 Field Notes

This day covers the second part of Project 7: Whitehouse Petitions in Hacking with Swift.

You can find the entire project I made to follow along in the folder of Day 33, but Day 34, in particular, focuses on several specific topics:

  • Rendering a petition: loadHTMLString
  • Finishing touches: didFinishLaunchingWithOptions

Rendering a petition: loadHTMLString

During our initial introduction to WKWebView, I was wondering whether or not there were still any compelling use cases for it now that SFSafariViewController has been introduced. WKWebView.loadHTMLString might be one example.

If we have some kind of dynamic HTML string that we want to use for rendering, this method can give us a style of creating our own views that SFSafariViewController doesn't offer. Our current app is a bit of a toy example — I'd probably create a custom, native UI and feed our petition data to its various elements — but it serves as a solid proof of concept. I can imagine a scenario where an API only returns HTML. And in that case, we could feed it straight in to loadHTMLString (perhaps after also checking for malicious script injections 👮‍).

Finishing touches: didFinishLaunchingWithOptions

One of the first hooks generated in a project's AppDelegate.swift file, application(_:didFinishLaunchingWithOptions:) is where we can perform set-up operations for our app when we know that it's just about to start running.

And that's the perfect place for configuring our UITabBarController, wiring up the two child view controllers we need it to manage.

if let tabBarController = window?.rootViewController as? UITabBarController {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let navController = storyboard.instantiateViewController(withIdentifier: "Petitions Nav Controller")

    navController.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 1)
    tabBarController.viewControllers?.append(navController)
}

In some cases, a storyboard might do, but on the scale of storyboard to code, the fact that our tab bar's two view stacks are pretty much identical pushes tips things towards the latter ⚖️.

Configuring the API URL

Our two view controllers do have on minor difference: their API URLs. One way to handle this is to have the view controller check its position within the tab par and infer which URL it should use:

if navigationController?.tabBarItem.tag == 0 {
    apiURLString = "https://api.whitehouse.gov/v1/petitions.json?limit=100"
} else {
    apiURLString = "https://api.whitehouse.gov/v1/petitions.json?signatureCountFloor=10000&limit=100"
}

I prefer a more top-down approach, though. Rather than making the petitions view controller aware of our tab-bar designs, we can store our API urls in an enum, and then have our code in application(_:didFinishLaunchingWithOptions:) decide which controllers get to use which URLs. Iterating on the earlier didFinishLaunchingWithOptions example, I came up with this:

if let tabBarController = window?.rootViewController as? UITabBarController {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let navController = storyboard.instantiateViewController(withIdentifier: StoryboardId.petitionsNavController)
    let petitionsViewController = navController.children.first as? PetitionsListViewController

    petitionsViewController?.apiURLString = PetitionsAPI.popularPetitions
    navController.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 1)
    tabBarController.viewControllers?.append(navController)
}

(Only one modification is used here, because I did leave the PetitionsAPI.popularPetitions as the default for the PetitionsListViewController).

🛠 Project Progress

Multiple tab views and details pages

🔗 Additional/Related Links