turing complete with a stack of 0xdeadbeef

Writing

I mostly write about Swift, Objective-C, iOS, open source, and other software development topics. Sometimes I write about the ethics of tech, labor, and politics. I also write satire pieces, personal essays, and notes on what I'm currently reading.

Introducing ReactiveCollectionsKit

A Swift replacement for IGListKit 18 October 2024

I recently released a new open source project called ReactiveCollectionsKit. It is a modern, fast, and flexible library for building data-driven, declarative, reactive, and diffable collections and lists for iOS. This library is the culmination of everything I learned from building and maintaining IGListKit, ReactiveLists, and JSQDataSourcesKit. The 4th time’s a charm! 😅 🍀 I truly hope this is the last UICollectionView library I ever write and maintain. I think it will be. You can find the documentation here.

Continue…

Kintsugi

16 October 2024

Kintsugi — no, not that Kintsugi — is the the Japanese art of repairing broken pottery. The process involves mending the breaks in the ceramics with urushi lacquer, essentially gluing the pieces together and filling in any gaps to smooth it out. At the end, you finish off the cracks with a gold powder, which highlights and emphasizes the flaws in the piece rather than attempting to conceal them. The result is a restored piece of pottery or teaware that can now be put back to use.

Continue…

SwiftUI app lifecycle: issues with ScenePhase and using AppDelegate adaptors

29 June 2024

SwiftUI introduced the ScenePhase API in iOS 14 and macOS 11. This was SwiftUI’s answer to handling application lifecycle events. At the same time, SwiftUI introduced UIApplicationDelegateAdaptor for iOS and NSApplicationDelegateAdaptor for macOS, which allow you to provide an AppDelegate on both platforms to receive additional application lifecycle events and other events that were missing from SwiftUI at the time. Unfortunately, many of those application event APIs are still missing and ScenePhase has a number of bugs (or at least, unexpected behavior).

Continue…

Swift concurrency hack for passing non-sendable closures

Uncheck yourself before you wreck yourself 05 June 2024
Updated: 05 June 2024

If you have attempted to adopt Swift Concurrency in your codebase, you have certainly needed to address dozens — likely, hundreds — of warnings and errors. Sometimes the issues can be resolved by addressing them directly. That is, your code was incorrect and you simply have to fix it to make it correct. In other scenarios, the resolution is not so straightforward. In particular, it is difficult to satisfy the compiler when working with APIs that you do not own that have not been updated for concurrency. Or, you may have found yourself in a situation where you know your code is correct, but the compiler is unable to verify its correctness — either because of a few remaining bugs in Swift Concurrency, or because you are using @preconcurrency APIs.

Continue…

Workaround: Xcode deletes Package.resolved file and produces 'missing package product' errors

29 May 2024
Updated: 30 May 2024

More and more Apple Platform developers are migrating away from CocoaPods in favor the Swift Package Manager, which is Apple’s first-party tool for managing and integrating dependencies. While it is still not quite a complete replacement for CocoaPods, it is getting closer. Unfortunately, SwiftPM’s integration with Xcode still has a number of shortcomings, even though it was introduced with Xcode 11 — 4 years ago. The worst bug is that Xcode frequently and randomly deletes the Package.resolved, which in turn produces dozens or hundreds of 'missing package product' errors. Here’s how I’ve worked around this bug on a team I work on.

Continue…

The curious case of Apple's third-party SDK list for privacy manifests

29 April 2024
Updated: 30 April 2024

At last year’s WWDC, Apple introduced privacy manifests. They recently sent out a reminder that the deadline for complying with these new requirements is May 1. Privacy manifests expand on the previously introduced privacy “nutrition labels” that are self-reported by developers and displayed on the App Store. Developers must start including a privacy manifest in their apps by the aforementioned deadline, but what’s more interesting is that Apple is, for the first time, imposing these new privacy rules on third-party SDKs as well. Even more interesting is the list of SDKs that Apple has published, which, upon inspection is quite bizarre.

Continue…

A simple fastlane setup for solo indie developers

22 January 2024

I recently setup fastlane for one of my indie apps, Taxatio, to automate uploading builds and metadata to the App Store — by far, one of the most tedious tasks of app development. While I had used fastlane extensively before when working on teams at companies, I had never actually set it up from scratch. In this post, I want to share how to do that, as well as a lightweight configuration that I think works well for solo indie developers — folks on a team of one!

Continue…

Swift protocol requirement quirks

17 January 2024

Perhaps “quirks” is not the correct description, but I recently encountered some unexpected behavior when modifying a protocol in Swift. While I was initially slightly confused, how Swift handles protocol requirements does make sense — conformances are more lenient than you might think!

Continue…

App Store screenshot requirements need to change

16 January 2024

Providing screenshots for the App Store has always been a tedious and time-consuming process. But as the number of differently-sized iOS devices has grown and changed over the years, it has become more difficult to manage. (This is why the developer community built tools like fastlane snapshot.) The screenshot requirements for the App Store have increasingly become a burden for developers, especially indies. With the Mac App Store, there are fewer hurdles and less strict requirements. However, if you are now targeting only the latest OS releases and latest hardware, the screenshot requirements for both App Stores are not only burdensome but they no longer makes any sense!

Continue…

A list of books I read in 2023

29 December 2023

Continuing another tradition, here are the books I read in 2023. Similar to my previous post highlighting my top posts of 2023, I also skipped publishing my reading list last year, for 2022. Again, I was simply too burnt out by the end of that year. I also did not read that much compared to previous years — thanks again to burnout. You can find previous years here under the #reading-list tag.

Continue…

Top posts of 2023

29 December 2023

To continue my (almost) tradition of sharing my top posts, here are my most popular posts of 2023. You can find previous years here under the #top-posts tag. Last year, 2022, is notably absent from this series — I was too burnt out last year (for a number of reasons) to write one of these posts. So as a bonus, I’ll include my top posts of 2022 here as well! As usual, all of my analytics data is publicly available, made possible by the excellent GoatCounter Analytics, so you can view it too.

Continue…

How to fix Mac menu bar icons hidden by the MacBook notch

16 December 2023
Updated: 29 May 2024

Last week I wrote about setting up a new MacBook Pro — my first Apple Silicon Mac, and thus my first MacBook with a notch. I lamented how poorly macOS interacts with the notch, specifically how menu bar apps and icons simply get hidden if you have too many to display. Lots of folks on Mastodon offered various solutions, and some readers emailed me with options as well. I figured it was worth making a separate post about this specific issue to list all of the workarounds and alternatives. It is clear that this is a widespread problem that users are having.

Continue…

Going Indie: bookkeeping and invoicing

07 December 2023

Welcome to the fourth (and I think final!) part of my going indie series! Previously, I discussed the exciting topics of business structure, taxes, and retirement. Today, I’m going to discuss two final topics: bookkeeping and invoicing. The first is about how to correctly track your income and expenses, and the second is about making sure you get paid! Because this is capitalism, baby — we are not here for passion, we are here to pay those bills.

Continue…

Setting up a new M3 MacBook Pro

04 December 2023

I typically try to keep devices for as long as I can — historically, that’s been around 5-6 years for laptops. During the Intel era of MacBooks, the year-over-year spec bumps were usually not impactful enough to justify more frequent upgrades. However, the transition to Apple Silicon has changed that. I recently upgraded to my first M-series MacBook Pro.

Continue…

How to fix malfunctioning AirPods

14 November 2023

A few weeks ago my AirPods Pro 2 (with Lightning, not USB-C) suddenly started acting buggy and weird. The case no longer made the chime sound when plugging them in to charge. I stopped getting “Left Behind” notifications from the Find My app. After updating to iOS 17, I could not get them to install the latest firmware, which enables the new features for Adaptive Audio, Conversation Awareness, and Personalized Volume. I had been trying for weeks to follow the magic steps that will trigger a firmware update with no luck. Even worse, after a full charge of both the AirPods and the case, the batteries for all of them would drain to zero percent within 2-3 days.

Continue…

GitHub Tip: using the involves filter

30 October 2023

When you work on a large team and are participating in many pull requests on GitHub, it can be difficult to keep track of everything you are working on. In addition to opening your own pull requests, you can be assigned to them, you can be requested as a reviewer, you can comment in discussion threads, and you can be mentioned by others. Each of these occurrences requires your attention — perhaps immediately, but always eventually.

Continue…

Swift URL absoluteString versus path

17 August 2023

Foundation’s URL (née NSURL) is a nearly ubiquitous API on Apple platforms. One of its shortcomings is that it is heavily overloaded – an instance of URL could represent a web URL or a file URL. While there are many similarities between accessing resources on a local disk or on a web server, I think there should be explicit types for each, say WebURL and FileURL.

Continue…

Going indie: business structure, taxes, and retirement

16 August 2023
Updated: 17 August 2023

Welcome to the third part of my going indie series! In the previous post, I discussed building a foundation, getting started, and finding clients. In this post, I am going to discuss many of the decidedly un-fun administrative aspects of being freelance and contracting like saving for retirement and — everyone’s favorite — taxes. Most folks consider these topics to be boring and tedious, but understanding them is critical to your success. The best approach is one of curiosity. As a software developer, you might find the task of optimizing (and minimizing!) your tax burden to be an interesting problem to solve — I definitely do!

Continue…

How to customize NavigationLink accessory views in SwiftUI

18 July 2023

In UIKit, UITableViewCell has a customizable accessory view. You can use one of the few accessory options that is provided by iOS by setting the accessoryType property, or you can provide a custom view using accessoryView, which can be any UIView. The equivalent of constructing a UITableViewCell with a chevron accessory in SwiftUI is using a NavigationLink. Unfortunately, however, SwiftUI does not provide an API to customize the accessory view for a NavigationLink — you are stuck with the default chevron.

Continue…