I’m live streaming my programming from start to finish on an iOS app to help folks explore and translate Scottish Gaelic phrases.
In the last post reviewing live streams 25-28, we installed our
UICollectionView (plus some gorgeous styling) for the Browse screen. There’s still a lot to do on it, though. Let’s get started.
First, there is a selector at the top of this screen that allows language learners to switch between “Phrases” and “Clans.” When they select “Phrases,” they’re supposed to see the collection view we worked on last time. When they select “Clans,” they’re supposed to see a
UITableView with the names of clans on it. We begin by trying to make that work (plus a brief interlude for fixing some constraints on the home screen):
In the end, the effort fails. I ended up needing to do some research on this, and it turns out there’s an established pattern for doing it. That pattern worked for us in the follow-up stream.
Tab Switching with Child View Controllers
UIActivityIndicators (wait spinners), and even
SkStoreReviewControllers (all of which we have seen) are child
UIViewControllers, but they don’t cede us much control. In fact, we had such insufficient control over the
UIActivityIndicator that we scrapped it for a prettier and more reliable solution that we built from scratch (here’s the video of that and the post where we talked about it).
Here, instead, we use two fully customized child
UIViewControllers to change a specific portion of what appears on the screen, while leaving another portion the same. iOS 13 took this concept even further with the introduction of the
SceneDelegate, the entree for multi-windowed applications.
UIViewControllers open up options for avoiding code duplication by ensuring that pieces of the screen with the same look and behavior in different contexts can operate from the same files. They probably succeed at that on the whole, though I’m sure there are a lot of occasions where these files contain code like “if the rest of the screen is displaying X, do A, otherwise do B.” They also make things really hard to test.
In iOS, my automated testing depends on the scenario.
- For convoluted logic inside an individual class, I test-drive with unit tests.
- For plumbing that chiefly inherits from iOS classes to facilitate user interaction, I build the components first, then hook up
XCUITestto the simulator, perform my user flow on the simulator, and add assertions that provide some modicum of regression checking (here’s a video of me doing that).
Because releasing an app to the App store is a time-consuming process, mobile apps do not loan themselves to continuous delivery. This means, if we have something on the app that we want to change rapidly or frequently, the app needs to fetch it from a server, which loans itself better to frequent or rapid deployment. This results in more logic ending up on the server, hollowing out the mobile app into a shell of user interaction pieces whose data gets fetched at runtime.
Also, because the device has limited computing power, we try to keep convoluted logic off of the mobile app; for example, instead of fetching a huge list in the mobile app and then filtering it to a small list client-side, we conserve device resources by including a query parameter in the server endpoint so that the filtering can happen server-side and the mobile app just displays what it gets.
This means that the code for a well-designed mobile app falls disproportionately into scenario #2 above rather than scenario #1. Pursuant to that, the mobile app tends to contain few unit tests, and my mobile app development flow uses relatively little TDD (especially on iOS—Android has much better tools to facilitate TDD). This is a very different flow to what you see me use on a Java, Python, or Ruby server app, for example.
Once we have our
UITableViewController, we need to style the cells:
On a personal note, I was sick during most of these live streams, so you see me trade out my usual habit of, you know, getting dressed, for lying on my couch in sweatshirts and bathrobes with no makeup, but THE SHOW MUST GO ON.
In the next few streams, we did some refactoring on the code to extract a generic service. We’ll cover that in the next Live Stream Director’s Cut.
If you liked this piece, you might also like:
The teaching series—I teach an online class about software engineering. Then I write about my teaching techniques.
The Raft distributed consensus algorithm series—Follow along step by step as I implement Raft in Python!
The techtivism series—About evaluating our production and consumption of tech products from an ethical perspective.