Using GitHub “Viewed” Checkbox

I’ve been using GitHub for years now, but I hadn’t really taken advantage of the “Viewed” checkbox on the right side of the file listing while reviewing PRs until a teammate pointed it out to me and mentioned its usefulness beyond indicating simply that the file had been viewed.

It turns out that if you use it in the way it was intended, the “Viewed” checkbox can save you some real headaches on a sizable PR, especially one that you know you’re going to have to revisit potentially more than once.

If you read the following description of the feature, it explains what it’s useful for:

Reviewing proposed changes in a pull request – GitHub Help

If the file changes after you view the file, it will be unmarked as viewed.

What that is really saying is that, in the time between your completing the first pass at a review of the PR, when you return to the list of files the files that have changed will be unchecked. Great! 👍🏻

Additionally, as the documentation states prior to the above quote, when you click the “Viewed” button, it also collapses the file down to a small rectangular region and hides the file contents.

What it’s not telling you is that GitHub is actually a little more helpful, because upon returning, it will actually do three things if a file has changed since your last visit:

  • Unchecks the “Viewed” checkbox
  • Adds a yellow box with a “Changed since last view” label in it, which is nice and visible
  • Expands the file on the page, making it obvious that the file has changed in the interim

These three things are super helpful at identifying the areas of code that have changed since you last viewed the code set. You can immediately see what has changed and focus your attention on those changed files.

This is a very useful feature, especially for large PRs. I probably wouldn’t use it much for smaller PRs, because they are easier to keep track of – but some PRs can get pretty big and include a large number of files, so they really benefit from this feature.

So, the next time you are facing a large PR, try using the “Viewed” checkbox on those files and see if it helps!

Older iPhone Simulators and macOS Catalina

The other evening, in the wake of a bit of nostalgia, I tested running an emulator project on an iPhone 5 simulator running iOS 10.3 in Xcode 11 (more on that in a future podcast episode).

It surprised me at the time—but it probably shouldn’t have—that I got the notorious “‘App Name’ has not been optimized for your Mac and needs to be updated.” alert box. In retrospect, this makes sense because iPhone 5 is a 32-bit device, and therefore so would its simulator counterpart. macOS Catalina doesn’t allow any 32-bit apps to run, so presumably we would have to resort to using the iPhone 5s simulator (or higher), otherwise we would see the “‘App Name’ needs to be updated.” message, and the simulator just would not run. I am not running Catalina yet, but when I upgrade I’ll definitely test this out to see if it’s a problem.

This finding will probably is not be a big issue for me, personally. I’m usually testing on newer iOS versions, with newer hardware and simulators. However, I can see where it would be helpful (or even necessary) to run an emulator that mirrored a particular user’s hardware for an older version of iOS.

Therefore, if you think that you might need to support older phones and older versions of iOS, then you may want to think twice about upgrading to Catalina, or perhaps have a machine or separate volume that boots into Mojave or High Sierra, just to be safe.

Enums and CaseIterable in Swift

In your journeys with Swift since 4.2 released, you may have seen the CaseIterable protocol when working with enums. Since this is a relatively new language feature in 4.2, you might wonder what that is or what it does. In this article on, Getting to Know Enum, Struct and Class Types in Swift, Adam Rush gives a very nice, concise description of what the purpose of CaseIterable is and how it works.

CaseIterable Enums in Swift are great for holding a list of items such as our example list of colors. To make enums even more powerful, Swift 4.2 added a new protocol named CaseIterable that provides a collection of all the values of the conformer.

At compile time, Swift will automatically create an allCases property that is an array of all your enum cases, in the order you defined them.

Using CaseIterable is very simple. All you have to do is declare the conformance in the definition of ColorName as shown below:

enum ColorName: String, CaseIterable {
  case black, silver, gray, white, maroon, red, purple, fuchsia, green, lime, olive, yellow, navy, blue, teal, aqua 

You can then use the allCases property whose type is [ColorName]. Add the following to the end of your playground:

for color in ColorName.allCases {
  print("I love the color \(color).")

In the console, you’ll see 16 lines printed — one for every color in ColorName.

The Curious Case of Audiobooks on iOS and macOS

I don’t use Audible (yet), but the situation regarding Audiobooks on macOS Mojave and iOS 12 feels a bit like a UX conundrum at the very least.

For starters, the Audiobooks feature resides in iTunes on macOS, but it’s in Books on iOS. I understand arguments for both, but it feels like Apple’s design or product team should have picked one app that the Audiobooks feature would live on from here on out, and then made the change for both platforms – even if that meant waiting for a future version of iOS and macOS. The current situation is just too confusing, even if it’s meant to be an interim solution. I am not yet running the macOS Catalina beta, so I’m not sure what the next version of macOS will bring for Audiobooks. Hopefully it will be an improvement.

Strangely, there appears to be almost no interface in iTunes Mac at all once you’ve acquired an audiobook. It’s just a list. Launching the audiobook in iTunes does not have any chapters listed, either. The audiobook is basically one long audio file from the looks of things (though it may have chapters or tracks under the hood).

Opening the audiobook in Books on iOS does present a list of tracks, which makes a little bit more sense to display it that way. However, it is odd that they don’t call the items in the list chapters, but that could just be an audiobook convention that I’m not familiar with. It just seemed that books have chapters… so why not audiobooks?

Additionally, navigating to and from the audiobook was a bit disorienting in Books on iOS. It was difficult for me to navigate around to see where the digital version of the printed book was. Eventually, I found it – and it turned out I needed to play with some sorting as well, and now that I’ve used it a few times on iOS it feels a little less clunky. But it definitely wasn’t an immediately intuitive experience, so clearly they have more work to do on the user experience side. Perhaps iOS 13 will bring improvements.

The current state of audiobooks on macOS and iOS feels like a mixed bag of user experiences, so it will be very interesting to see what Apple does in the future for Audiobooks support in macOS Catalina and iOS 13.

How To Configure Charles Proxy to Debug SSL Connections from iOS Apps

If you’re doing extensive debugging and introspection with your web APIs (or perhaps debugging Web Views), here’s how to configure Charles to proxy SSL connections from the Simulator and on-device:

SSL connections from within iPhone applications • Charles Web Debugging Proxy

As of Charles v3.9.3 there is an item in the Help menu, “Install Charles CA SSL Certificate in iOS Simulators”, which will automatically install Charles’s SSL CA certificate in your iOS Simulators.

How #available works in Swift

This article from the Big Nerd Ranch blog goes back to 2016, but it’s a great little rundown by Mark Dalrymple of #available, introduced back in Swift 2.0.

Hi! I’m #available!

Sometimes we just use language features like this and don’t really think about what’s going on under the hood when we use them, or perhaps we have a mental model based on past assumptions. However, Mark does a an excellent job filling in some of the details on this handy feature of Swift, explaining not only what it is but also what it is not.

The article also clarifies Xcode’s Target SDK version and Deployment Target version, which can initially be a point of confusion to many developers on the iOS platform.

Here’s a great summary of the article from the article itself (a TLDR;):

The take-away points: #available is not #if—it is not conditional compilation based on OS platform. Instead, at compile time, #available tells the compiler to temporarily raise the SDK level above your deployment target so that you can safely use newer API. At run time, the code will execute depending on the version of the OS the app is running on.

Handy Swift Resource: Hacking With Swift’s Auto Layout Cheat Sheet

This is a pretty great one-stop-shopping resource for Auto Layout by Paul Hudson.

The Auto Layout cheat sheet – Hacking with Swift

Auto Layout is a powerful tool for creating flexible, maintainable rules for your user interface. It can also be a real brain vortex if you’re unlucky – it’s something that makes hard things easy and easy things hard.

To help relieve the pain, in this article I’ve put together code snippets to solve a variety of common Auto Layout problems: creating constraints, animating constraints, adjusting constraints at runtime, and more.

As with all of Paul’s articles, it’s well thought out, and it’s a useful resource to stash away for the next time you need to do in-code work with Auto Layout and Swift.

It is disappointing that he does not use the word “vexing” anywhere this blog post as I had thoroughly expected him to do (and would have been so appropriate in any article about Auto Layout), but the tips are so good, I’ll overlook it this time.

Excellent resource.

How to Force Bluetooth Headphones to Use Internal Microphone in macOS

I love using my AirPods and my Urbanears Plattan 2 headphones with my Mac.

However, when macOS uses the microphone in AirPods or the Urbanears, the audio in the headphones goes to mono, sounding like an AM radio. It turns out that if you select “Internal Microphone” from Sound Preferences (or use the shortcut of Option-clicking on the Sound icon in your menu bar, and select “Internal Microphone” from the “Input” section), then your headphones go back to stereo and sound awesome again.

The problem is that—at least for me and some other users—macOS always selects the headphones’ microphone as the Input device when you connect your AirPods or other bluetooth headphones.

So I wanted to find a solution to this. Even if it involved coding up a solution.

Turns out there’s a really interesting AppleScript-based solution here:

Ask Different (Stack Exchange) – How to always use internal microphone?

I was fully prepared to do the AppleScript thing, or even go the extra step (as my reply to that solution suggests) and build a Mac menu bar app to handle this. But then I stumbled on this other solution that requires no coding (AppleScript/Swift/ObjC/Other) in High Sierra, and it turns out it’s super easy to configure.

Disclaimer: Please note that the answer was in the comment section of the article and it seems to work on High Sierra (I’m on 10.13.6), but I don’t know if this works on Mojave and beyond.

Open the standard “Audio MIDI” utility, and click the + at the bottom to create an Aggregate Device. Then select the Internal Microphone as the only component in this aggregate device and select it as the default input. For some reason this prevents Mac OS X from selecting the Bluetooth Microphone from now on and it will stay on the internal one when you reconnect.

After creating that aggregate input, go to your usual System Preferences -> Sound -> Input (tab)


Pro Tip: To get to Audio MIDI Setup quickly, an easy way is to just invoke your Spotlight Search (Cmd-Spacebar or whatever you have it mapped to), and type “Audio” – it should pick it up, or at least be in the list of results.

The great news is that—at least in my preliminary tests with disconnecting and reconnecting my bluetooth headphones—it appears macOS does in fact hold on to the Internal Microphone setting. My one concern at this point is whether that would impact connecting other microphones. I suspect it will be a matter of manually selecting the microphone in the Sound Preferences (or menu), but I can live with that because it’s the much-less-common scenario for me.

When Worlds Collide: How to call complex Objective-C selectors from Swift

When developing in Swift, you will eventually need to interact with Objective-C APIs. Most of the time this is fine, and fairly straightforward to do using #selector.

However, every once in a while you will need to invoke an Objective-C selector that you did not write (usually when the selector is part of the iOS or macOS SDK), does not have a unique signature, or is just pretty hard to figure out.

This article put out by Big Nerd Ranch’s Mark Dalrymple is an excellent rundown of how to properly invoke Objective-C selectors from Swift. He even covers really hairy signatures that may be very difficult to come up with on your own at first glance.

Big Nerd Ranch — Hannibal #selector

The selector is key to Objective-C’s dynamic runtime nature. It’s just a name that’s used, at runtime, as a key into a dictionary of function pointers. Whenever you send a message to an Objective-C object, you’re actually using a selector to look up a function to call. Sometimes selectors bubble up in Cocoa/CocoaTouch API, and you will need to deal with them in Swift.