A few months ago, I shared my notes and resources for learning about compilers and LLVM. It turned out to be pretty popular and folks seemed to find it useful. So I decided to do it again, but this time for SwiftUI. However, unlike learning about compilers and LLVM, I am not declaring bankruptcy with learning SwiftUI. While I have still not written a single line of SwiftUI code, I know I eventually will.
Lately, it feels like every few days someone is sharing a new Xcode tip on Twitter or on their blog. They range from hidden settings to features I simply never knew about. I started saving links and planned to add a new “Xcode tips” section to my TIL repo on GitHub to reference later. But as I started, I realized that the resulting markdown file would not be easily discoverable or shareable. I thought, wouldn’t it be nice if the iOS and macOS developer community had a single place to find and share Xcode tips?
Updated: 06 Apr 2021
As I continue to pursue Mac app development more seriously, I can build on and borrow from my many years of iOS experience. While many aspects of writing Mac apps are very similar to iOS, or at least somewhat familiar, other aspects are quite different. One of the big differences is testing, and deciding how many versions of macOS to support.
The Touch Bar on my MacBook started freezing and experiencing UI glitches recently. It was completely unresponsive. At the time, the only way I knew to fix it was to reboot my entire machine, which felt ridiculous. Luckily, there is a better way.
This is a first for me. I returned to my MacBook after leaving it for a couple of hours, and it was shutdown even though I left it powered on. The machine was idle. I didn’t have any specific tasks running. I figured it might have been a macOS kernel panic, but upon rebooting I discovered that the crash was caused by bridgeOS.
I was never a fan of failable initializers in Swift. I do not think this is the correct place to fail and return
nil most of the time. Of course, there are exceptions where a failable initializer is appropriate. But there is another behavior of which to be aware. When constructing a class via a failable initializer,
init?() — or a throwing initializer,
init() throws — the deinitializer,
deinit, is not called if initialization fails or throws, respectively.
Updated: 06 Oct 2020
Out of nowhere today, when I tried to run
pod install on my machine, it could not be found. Uh… what?
Updated: 06 Oct 2020
Update: This post was originally written during Xcode 12 beta 3, but has been updated to reflect the final release of Xcode 12.
Xcode 12 was released and it includes a change to how tabs and navigation work. In Xcode 12, the tabs have their own tabs. It makes no sense to me. I know we are supposed to be nice to each other about software, but this new UI/UX is beyond incomprehensible. What made it worse is that this new “tabs within tabs” was the default setting (overriding preferences I had previously set) and I could not figure out how to restore the previous (desired) behavior.
While debugging some code the other day, I wanted to verify the behavior of global variables and static members in Swift. I vaguely remembered from the early days of Swift, that
static let members and global constants were atomic and computed lazily — one of the many improvements over Objective-C.
I try to have only one Xcode installed at a time for simplicity and tidiness. But such a setup is rare as we often must manage stable releases and beta versions simultaneously.
When I first upgraded to macOS Catalina, there was a “Relocated Items” folder on the desktop. Well, actually it was an alias to
/Users/Shared/Relocated Items/. This was expected, given the new “security features” in Catalina, which includes a new read-only system volume. What I did not expect was to see this folder reappear with every single update.
I’ve been working on two small libraries for building menu bar Mac apps and now they are both open source with initial 1.0 releases.
Last year Xcode 11 was released with integrated support for the Swift Package Manager. For a couple of small projects of mine, I decided to try using it to manage dependencies instead of CocoaPods. Overall, using SwiftPM was a great user experience, but (as expected) it has clear shortcomings due to its lack of maturity.
I recently discovered that unit tests and UI tests for a macOS Xcode project will fail with obscure error messages if the hardened runtime is enabled. It took me awhile to realize what the actual source of the problem was, because the error messages led me in the wrong direction. Hopefully this will save you some time.
Xcode has a great UI for setting and editing breakpoints. I use breakpoints all the time while working and debugging, but I want to share another, unconventional way that I use them.
I love OmniFocus. It is an indispensable app for me and a great Mac app. For managing and organizing to-do lists and personal projects, there is nothing better. Being a great Mac app means adopting behaviors that users expect, conforming to macOS UI/UX paradigms, and for the truly great mac apps it means being scriptable. I want to share two AppleScripts that I wrote for OmniFocus to automate one of my common workflows.
I recently needed to determine when the user has manually switched between dark mode and light mode on macOS. In my menu bar app, Lucifer, the icon reflects the current appearance setting when you change it from the app — an inverted pentagram for dark mode and an upright pentagram for light mode. But there’s a bug. If the user manually changes the appearance setting from System Preferences, or if they are using the new “auto” setting in macOS Catalina, the icon gets stuck in its previous state.
Unfortunately, iCloud does not have a good reputation for being reliable, especially during beta releases of iOS and macOS. Yet a lot people still use it, often without any problems. I still use it, despite a few bad experiences in the past, because the best alternatives are questionable for other reasons. I’ve had good luck with iCloud Drive for the past few years, but I am terrified and paranoid of getting caught in the middle of an iCloud clusterfuck, so I backup what I have in iCloud periodically using
I recently released a menu bar Mac app called Red Eye. It’s free and you can download it here. It prevents your Mac from going to sleep. Yes, it is a clone of the beloved Caffeine. And yes, it is the second menu bar app that I’ve made recently. It is notarized by Apple, so you shouldn’t have any problems installing it. I hope you enjoy it!
This isn’t complicated, but I found it confusing. Perhaps I am spoiled by the more modern APIs in
UIKit. When writing Lucifer, a menu bar app, I wanted to have different actions for left-clicking and right-clicking on the button in the menu bar. To my surprise, this was much more cumbersome than I expected.
I made my first Mac app — Lucifer. It is a menu bar app that allows you toggle Dark Mode on and off in macOS Mojave. To be honest, it feels like a stretch to actually call this a Mac app. It is less than 100 lines of code in a single
AppDelegate.swift file and the meat of the program is an AppleScript that tells System Preferences to enable or disable Dark Mode. As an iOS developer, much of the experience was familiar. The most salient aspect, however, was learning the frustrating and obscure details of app sandboxing, the “hardened runtime”, and app notarization — altogether it was like visiting hell and giving Satan a bubble bath. Appropriate, I suppose.
Updated: 05 Jan 2019
When you file a radar for a bug on one of Apple’s platforms, you should (usually) always attach a sysdiagnose. A sysdiagnose provides a lot of helpful information for the person who is trying to understand how the bug happened. Amongst other things, it contains logs from various parts of the OS, and all recent crash logs. Without it, the person on the other end of your report inside Apple may not be of much help. On macOS running sysdiagnose is somewhat common, but what about iOS?
The Swift type-checker remains a performance bottleneck for compile times, though it has improved tremendously over the past two years. You could even say the type-checker has gone from being drunk to sober. To help users debug these issues, awhile back Jordan Rose added a frontend Swift compiler flag that would emit warnings in Xcode for functions that took too long to compile, or rather took too long to type-check. In Xcode 9, there’s a new, similar flag for checking expressions.
Swift is still young and ever-changing. With each release, we have seen dozens of tweaks, additions, and deletions. And there is no reason for us to think that this rapid evolution will decline anytime soon. To remind us of exactly that, the latest post on Apple’s Swift Developer Blog introduces a new feature in Swift 1.1 in Xcode 6.1 — failable initializers.