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 raywenderlich.com, 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 Setup.app” 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)

Source: http://ssrubin.com/posts/fixing-macos-bluetooth-headphone-audio-quality-issues-with-hammerspoon.html#comment-4018174387

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.

Fixing Git SSH After Upgrading to macOS Sierra

Yes. I’m a latecomer to the Sierra game (due mainly to an audio hardware driver I had to wait on to be upgraded to Sierra, which finally was updated but probably won’t be updated to High Sierra…), and most developers have probably already run into this problem and have dealt with it accordingly. However, I thought it might be a good idea to capture this here for posterity…

Just this morning, immediately after upgrading to macOS Sierra, I experienced a problem by which Git began incessantly asking for my passphrase. This was an unwelcome surprise to me, but thankfully there’s a reasonably simple fix, thanks to this SuperUser suggestion:

macOS keeps asking my ssh passphrase since I updated to Sierra – Super User

In the latest version of macOS (10.12.2), this is easy to fix. Just edit your ~/.ssh/config and enable the UseKeychain option:

Host *
 UseKeychain yes

There is no need to change anything else. Now everything works the way it used to work before the latest updates. You do not need to add keys to ssh-agent.

In my case, I couldn’t just edit the config file in question, because it didn’t exist. Therefore, I had to create the config file in my ~/.ssh directory with the information mentioned in the SuperUser post.

Thankfully, after creating the file, re-launching Terminal, and entering my credentials one final time, it seems to have worked and Git is happy again.