Using Type Markers for ‘is’ Type Predicates to Cover Generic Types

Maybe you have some old code (you wouldn’t write this nowadays, of course) that uses someValue is SomeType checks. Maybe you need to check if someValue is a generic type, like the following Box: Then your is predicates won’t work: The good news is that since you treat the concrete type as a mere marker, you can express this condition with a type marker protocol:

Continue reading …

Dependency Injection via Protocol Composition

Watching Stephen Celis’ “How to Control the World”, NSSpain 2018 presentation, one of the common Swift/iOS patterns he brings up caught my attention.

It’s this piece of code:

protocol APIClientProvider {
  var api: APIClientProtocol { get }

protocol DateProvider {
  func date() -> Date

extension World: APIClientProvider, DateProvider {}

class MyViewController: UIViewController {
  typealias Dependencies = APIClientProvider & DateProvider

  let label = UILabel()
  let dependencies: Dependencies

  init(dependencies: Dependencies) {
    self.dependencies = dependencies

  func greet() {
    self.dependencies.api.fetchCurrentUser { result in
      if let user = result.success {
        self.label.text = "Hi, \(! It’s \("

I never saw usage of a typealias Dependencies declaration that uses Protocol Composition to declare which dependencies are needed (expressed as 1 type being the combination of all actual dependencies).

This was news to me, so I wonder if you ran into something like this out there in the wild.

Show Referrers in TelemetryDeck for Web with a TopN TQL Query

The current TelemetryDeck for web setup guide (version of 2023-12-01) is quite simple. Insert this into your HTML, and you’re set: From that point onward, you’ll be collecting signals per web site hit. Internally, the signal’s type is "type":"pageview". These signals will include all the usual suspects: browser, os and version, url (the page that was visited), and also referrer (where visitors may have come from, following a link).

Continue reading …

How Long Does a Disk Preclear in Unraid Take for 12TB of Data?

I’m upgrading my 4TB drives in the NAS to 12TB drives. “Let’s be clever,” I thought (foreshadowing), “and do two things in parallel!” So installing the next drive into the disk array of my Unraid NAS, I let Unraid do these tasks: Does that speed things up, though? No, not at all, because Preclearing a disk takes 3x as long: Around 21 hours for each step that checks every nook and cranny of the HDD.

Continue reading …

Not Quite 100% SwiftUI – Time Makes Perfect

Marin’s Swift Heroes 2023 talk was just uploaded yesterday. It’s called “A 100% SwiftUI App”, and I believe you should watch it, because it’s not actually about what it says on the tin!

Marin Todorov: “A 100% SwiftUI App”, Swift Heroes 2023 talk

Marin’s a charismatic presenter and excellent storyteller. (He also later admits it’s his 65th tech talk, wow!)

There are a couple of gems:

One is the use of the (ficticious) AppKit property leftShiftPressed­InCombination­WithTouchBar­WhereAvailable­RepresentsMouseEvent = 6 to illustrate that over the past 35 years, AppKit has become quite weird, actually.

Another is Marin’s summary of the whole situation right afterward:

Time makes perfect;
but also adds a hundred properties to every class.
– Marin Todorov, 2023

So I’ll spoil one more detail: “A 100% SwiftUI App” is not actually a hard sell to do all of your apps with 100% SwiftUI. Quite the opposite.

I won’t spoil why, though.

Portable Painter Micro Palette

Teaser image

Maybe you don’t know, but I’m organizing a local Urban Sketchers group in Bielefeld for 6 years. We meet regularly and draw and paint together. And that’s how I met your mother,
– I’d say if you were my child. As a birthday present, I got a Portable Painter Micro palette from my wife (she’s the best). It’s a watercolor palette holding 6 half-pans, and she picked colors to match Teoh Yi Chie’s 2021 palette, who historically very vibrant and fun paintings!

Continue reading …

Year 36, a 🎂 Retrospective

I’m usually not doing birthday posts, but a lot has happened, and it feels like more change is about to come. Ok, that’s the biggest change, and I could stop here. But there were other things that do pale in comparison, but which were still important: Aggregated time tracking stats on my computers (numbers differ from screenshot because some items appear again further down, e.g. for different app bundle IDs):

Continue reading …

Kill Unsaved Emacs Buffers UX: Replacing Yes/No/Save with Meaningful Options

Teaser image

Upgrading to Emacs 29.1 worked like a charm. There’ve been a couple of small neat additions next to all the big changes like native tree-sitter support – and there’s one in particular that you could say I almost hate. When I compose email and decide to discard everything, I’m politely being asked whether I want to kill (aka ‘close’) the buffer and discard all changes. This applies to all other buffers that haven’t been saved, too, but I mostly run into this with email.

Continue reading …

Making Your App Extensible with JavaScriptCore: Annotated Presentation with Full Transcript

Teaser image

Last year, I posted my presentation video and slides for the CocoaHeads Aachen talk “Making Your App Extensible with JavaScriptCore”. Today I read about Simon Willisons’s presentation annotation tool. It’s a simple HTML file where you can put your slides, have Tesseract generate alt-text for each, and annotate the whole thing with simple Markdown. The generated output is HTML. It is genius. I love it, and here’s the slides + transcript (which I happen to have from editing the video anyway) of the JSCore talk.

Continue reading …

SwiftData: Store Image Data, but Actually Outside the Database

Tunds ( shared a video tutorial about SwiftData this weekend.

I hadn’t looked at SwiftData at all until now. The thumbnail read “Store Images in SwiftData”, and I was immediately worried: I recall it’s a bad idea to store megabyte upon megabyte of binary data inside the DB, assuming it’ll be using a BLOB column.

Turns out that SwiftData isn’t that simplistic and my assumption is wrong if configured properly!

SwiftData models can manage storage outside to the database. That’s what @Attribute(.externalStorage) is for: “Stores the property’s value as binary data adjacent to the model storage.”

Check out Tunds’s video, See How To Store An Image In SwiftData 📸. The last chapter is about this attribute.

Great to hear that SwiftData takes care of this so conveniently.

Async XCTest Assertion Helpers

SwiftAsyncAssert by Angu (

Instead of writing

import XCTest

func test_should_succeed() async {
    do {
        let isTrue = try await shouldSucceed()
    } catch {
        XCFail("Should not throw an error")

conveniently write

import SwiftAsyncAssert

func test_should_succeed() async {
    await AsyncAssertTrue(try await shouldSucceed())

func test_should_throwError() async {
    await AsyncAssertThrowsError(try await shouldFail())

Less code for your convenience when testing!

I ran into this, too, recently and wondered how everyone’s dealing with this. Because this is so annoying, I expected more outcries on the interwebs every day.

Maybe nobody is writing tests?

Either way: These helpers look very nice, and I’ll try them for sure. Should be part of the XCTest libray in my opinion. I seriously wonder why there’s no async XCTest assertion functions for this already.

If you’re just running into this for main actor isolation: One workaround that got suggested to me is to annotate the XCTestCase subclass itself with @MainActor to circumvent having to await isolated calls everywhere. (That doesn’t help for non-main actor-isolated calls, obviously.)

Inverted E-Mail Blockquotes

Is the following a thing in the U.S. of A, or common anywhere else, and I just didn’t notice that? For about a year, some people reply to email questions by interspersing their replies with my questions. That’s good in general to provide context. But what I don’t understand is the practice of adding the > at the beginning of lines of their replies.

Continue reading …

Super Saturday Sharefest: Matt Massicotte’s XPC Work

Ok ok, I know Super Saturday Sharefest is not a thing, but it’s too late for Follower Friday, alright? I want to give a big shout-out to Matt Massicotte of ChimeHQ for dropping another awesome Swift open source package that makes using XPC Swift-ier. I’m really grateful for all the amazing work Matt has been doing and for sharing it with the community.

Continue reading …

WordCounter v1.6.6 Released

Teaser image

I have released a maintenance update to my app, WordCounter. Check out the release notes.

Some old code went out, some updated components went in. Most notably the date range picker from the statistics:

Latest date range picker of your stats

Since this update is built on modern macOS, I can’t support anything older than macOS 10.13 anymore without hassle, so that’s what’s required now.

I hope to have something fancier in store for the 10-year anniversay next year!

Get the WordCounter app for Mac.

Swift Pattern Matching with Extra Conditions, and the Value of Syntax Summaries

Natalia Panferova writes about Swift enum pattern matching with extra conditions and goes over:

  • switch-case statements,
  • switch-case statements with where clauses,
  • for-in loops with where clauses,
  • while loops with extra conditions (case let matching),
  • if-case statements.
  • (Missing, for completion: catch ... where in try-catch blocks.)

I believe there’s tremendous value in summaries like these to learn the Swift programming language and its syntax: these short summaries show a slice of different aspects of the language in close proximity.

The Swift language book tells you all about the structural programming features one after another in the Control Flow chapter: if, for, while, etc.

It also has a section on where, but that’s limited to the switch conditional statement.

The section on for loops doesn’t mention where clauses at all! You need to go to the Language Reference part of the book, where the formal grammar is explained, to read that a where-clause? is allowed.

for-in-statement → for case? pattern in expression where-clause? code-block

So a post like Natalia’s reminds us about the similarity of different aspects of the Swift programming language.

It’s zooming in on where-clauses, and so the reader gets to know a different “view” into the syntax as a whole that is different from the book’s presentation.

This should be very valuable to get from beginner-level understanding of “I can do things in Swift” to a deeper understanding of recognizing similarities across different aspects of the programming language.

These should, in my opinion, be included in the language’s handbook to help with “deep learning”. Until then, I’m glad we have posts like Natalia’s!

11 or so Android Ebook Reader Apps for Academic Writing Workflows: Annotations are Hard

Here’s my personal comparison of Android ebook readers for my Boox eink tablet. I would love to add drawings as annotations. Ratta Supernote devices do this splendidly by storing the pencil input directly, without handwriting recognition. (Example here.) This is the gold standard. Everything else requires multiple apps (to draw a diagram, for example) and import/export (of notes or EPUB book locations), which is also acceptable, but not ideal.

Continue reading …

Boox NeoReader Annotation Export Is Meh

When you use the built-in “NeoReader” on a Boox tablet, you get the best pencil input and quite good highlighting and annotation support. If you don’t have a Onyx Boox eink tablet with that app installed, don’t bother looking for it on the Android/Google Play Store – that app is not available anywhere else, it seems. And the app of the same name on the Play Store is a QR Code Reader.

Continue reading …

Detach Xcode Console – via Terminal

Teaser image

I have been complaining on social media about the Xcode Console sticking to the bottom, and how I’d prefer a horizontal split etc. And there have been good suggestions to e.g. open a new Console tab or window. (Thanks Dominik Hauser for the tip!) That didn’t stick because I needed to adjust the Xcode behaviors and sometimes that didn’t compose well with what I’ve been doing.

Continue reading …

Website Rank in Common Crawl’s C4 AI Dataset

The Washington Post published an article, “Inside the secret list of websites that make AI like ChatGPT sound smart”, that visualizes a bit of the C4 data model via websites that have been crawled.

Scroll down a lot to “Is your website training AI?” (direct anchor link), and you can enter a domain (e.g. yours!) to see how much that page has contributed.

Rank Domain Tokens Percent of all Tokens
11 55M 0.04%
106,350 190k 0.0001%
328,137 71k 0.00005%
718,385 32k 0.00002%

Can’t beat a community effort like a forum, no matter how much or how long I post :)

Got the link and the idea to check my sites from

Update 2023-04-20: I should’ve checked the Post’s claims, first; they say it’s Google’s dataset, but that seems to be wrong. Here’s a short summary of the C4 dataset I could find:

What is C4?

The Post link to a research paper. That, and the article itself, reference C4: this stands for “Colossal Clean Crawled Corpus”, from The dataset is available on Hugging Face.

Hugging Face’s “Models trained or fine-tuned on c4” sidebar contains Google-owned repositories, but Common Crawl doesn’t appear to be affiliated with Google directly. Wikipedia indicates that the Common Crawl foundation is founded by Gil Elbaz whose company “Applied Semantics” was acquired by Google. But the Common Crawl foundation isn’t, as far as I can tell.

The dataset is likely used by AI, including Google’s, but that’s different.

To be fair, I got the idea that this is Google’s from JWZ’s post title, “I’m the Googlebot. I’m here to index you. Please hold still.” first, and then didn’t get rid of this idea when writing this post.

Sorry for the confusion – I updated the post’s title!

Fetch Personalized Command Explanations with ‘um’ from Your Terminal

Teaser image

I stumbled upon this page: Dave Gauer describes how he has a shell script, um, that he can use as a man replacement to help remember how to use a command. Dave’s implementation uses the cards} from his own Wiki, because the um pages there are “consolidated, I won’t forget about them, it’s easy to list, create, and update pages.” (To be honest, though, I can’t figure out where his um cards actually are, and what they look like.)

Continue reading …

Create FastMail Masked Email Addresses with maskedemail-cli

I’m a happy FastMail user. If you want to be a happy, too, use my referral code for 10% off of your first year (and I’ll get a discount, too!) → I never used their Masked Email feature, though, because it’s so cumbersome to create these addresses from the web UI. I all but forgot about this feature until today, when I looked for something else in my settings.

Continue reading …

VIPER Added to the Wiki

I was adding “tech stacks” to my CV and figured I might as well link the tech to articles or overviews on my page.

The ‘wiki’ pages I added some time ago are the best places to summarize topics and embed a list of related posts. So I added a page about VIPER and briefly had a look at my old posts.

On a side note, it’s funny how this approach looked kind of popular for a while, but never really caught on. Another example that programming is a pop culture. VIPER never made the Top 10. While it’s still an approach that does what it set out to do, the shorter ‘VIP’ tried to supplant it later, but the much less opinionated [view] coordinators really took the stage. (Crazy that Soroush’s post is from January 2015, which is 8 years ago.)

Copilot for Xcode Works Okay

I’ve never touched GitHub Copilot in all these years, but everyone seems to be very happy with it. People recommend Copilot for all kinds of refactorings and repetetive tasks. So I figured I might give it a try and see how it works. Just yesterday, I used the Copilot Xcode plugin to write a lot of boilerplate for me. I can confirm it does its job.

Continue reading …

TableFlip v1.4.1 Released

Teaser image

TableFlip v1.4.1 passed App Store review and is now released: In my original draft for this post I wrote this: Direct customers got the update on Monday already. This plan was somewhat sort of holding up, but it was actually last week that I intended to publish it. And direct customers need to download the latest version manually, because I broke the auto-updater in the previous version.

Continue reading …

PSA: FileManager.trashItem (Maybe) Uses NSFileCoordinator Under the Hood Automatically, So You Shouldn’t to Prevent Deadlocks

Users of The Archive and Dropbox have reported issues with deleting files in their Dropbox-managed folders in the past weeks: the app would beachball forever. Apparently, Dropbox’s recent migration from ~/Dropbox to ~/Library/CloudStorage affects this. I had the occasional Google Drive user in the past months report similar issues but couldn’t make much sense of it – until now.

Continue reading …

Xcode Requires A Lot of Data for Swift Package Resolution

Teaser image

This picture shows one of the weird annoyances with Xcode and Swift packages. One package resolution step swallowed 45MB of my data. You’ve likely heard it elsewhere: when iOS developers need to work with Swift packages and Xcode but have a shoddy internet connection, tough luck! Xcode will fail to build because it’s “Resolving Packages” step inevitably fails.

Continue reading …

The Difference between Entity and Value Object, and How They Relate to Swift’s Identifiable and Equatable Protocols

Helge Heß recently posted on Mastodon that he “still find[s] it disturbing how many #SwiftLang devs implement Equatable as something that breaks the Equatable contract, just to please some API requiring it. Feels like they usually should implement Identifiable and build on top of that instead.”

Continue reading …

woolsweater’s SF Symbols Modeline

Teaser image

After discovering how to use SF Symbols in Emacs on Mac, folks on Reddit shared links where Josh Caswell (known by his handle “woolsweater”) did stuff like this ages ago.

This is how the SF Symbol glyphs render if you can actually see them. I.e, outside the browser’s code preview.

Check out his DOOM Emacs compatible, doom-modeline based SF Symbols iconification in sfsymbols-modeline.el.