After my previous post Tracking renamed files in Git, here’s another entry in my ongoing series “I thought git mv was useless but I was wrong”. This one’s especially relevant to users on macOS and Windows, where the file system is case-insensitive by default. More precisely, APFS on macOS is case-insensitive but case-preserving by default. That is, A.TXT and a.txt…
Ole Begemann
https://oleb.net/blog/ · 20 posts · history since 2022 · active
16 Dec 2025
15 Dec 2025
Git famously doesn’t track file renames. That is, Git doesn’t store the information “file A has been renamed to B in commit X”. Instead, Git stores snapshots of the repository at each commit. It then uses a (customizable) heuristic during diffing to guess at likely renames: “File B in commit X is new, and file A has been deleted. B…
5 Mar 2024
The Swift website provides nightly builds of the Swift compiler (called toolchains) for download. Building with a nightly compiler can be useful if you want to check if a bug has already been fixed on main, or if you want to experiment with upcoming language features such as Embedded Swift, as I’ve been doing lately. A toolchain is distributed as…
29 Feb 2024
You may have noticed that the Swift compiler automatically treats the closure of a DispatchQueue.main.async call as @MainActor. In other words, we can call a main-actor-isolated function in the closure: import Dispatch @MainActor func mainActorFunc() { } DispatchQueue.main.async { // The compiler lets us call this because // it knows we're on the main actor. mainActorFunc() } This behavior is…
24 Mar 2023
And what it can teach us about SwiftUI’s stack layout algorithm I have one more thing to say on the relative sizing view modifier from my previous post, Working with percentages in SwiftUI layout. I’m assuming you’ve read that article. The following is good to know if you want to use the modifier in your own code, but I hope…
23 Mar 2023
SwiftUI’s layout primitives generally don’t provide relative sizing options, e.g. “make this view 50 % of the width of its container”. Let’s build our own! Use case: chat bubbles Consider this chat conversation view as an example of what I want to build. The chat bubbles always remain 80 % as wide as their container as the view is resized:…
21 Mar 2023
Problem The Photos app on macOS doesn’t provide a keyboard shortcut for the Export Unmodified Original command. macOS allows you to add your own app-specific keyboard shortcuts via System Settings > Keyboard > Keyboard Shortcuts > App Shortcuts. You need to enter the exact spelling of the menu item you want to invoke. Photos renames the command depending on what’s…
9 Mar 2023
I rarely participate actively in the Swift Evolution process, but I frequently refer to evolution proposals for my work, often multiple times per week. The proposals aren’t always easy to read, but they’re the most comprehensive (and sometimes only) documentation we have for many Swift features. For years, my tool of choice for searching Swift Evolution proposals has been Karoy…
27 Feb 2023
Foundation overloads the pattern matching operator ~= to enable matching against error codes in catch clauses. catch clauses in Swift support pattern matching, using the same patterns you’d use in a case clause inside a switch or in an if case … statement. For example, to handle a file-not-found error you might write: import Foundation do { let fileURL =…
31 Jan 2023
I know I’m almost a decade late to this party, but I’m probably not the only one, so here goes. Double Fine Adventure was a wildly successful 2012 Kickstarter project to crowdfund the development of a point-and-click adventure game and, crucially, to document its development on video. The resulting game Broken Age was eventually released in two parts in 2014…
15 Dec 2022
I wrote an app called SwiftUI View Lifecycle. The app allows you to observe how different SwiftUI constructs and containers affect a view’s lifecycle, including the lifetime of its state and when onAppear gets called. The code for the app is on GitHub. It can be built for iOS and macOS. The view tree and the render tree When we…
24 Nov 2022
The clipped() modifier in SwiftUI clips a view to its bounds, hiding any out-of-bounds content. But note that clipping doesn’t affect hit testing; the clipped view can still receive taps/clicks outside the visible area. I tested this on iOS 16.1 and macOS 13.0. Example Here’s a 300×300 square, which we then constrain to a 100×100 frame. I also added a…
10 Nov 2022
On the positioning of the .animation modifier in the view tree, or: “Rendering” vs. “non-rendering” view modifiers The documentation for SwiftUI’s animation modifier says: Applies the given animation to this view when the specified value changes. This sounds unambiguous to me: it sets the animation for “this view”, i.e. the part of the view tree that .animation is being applied…
12 Oct 2022
Mac apps built with Xcode 14.0 and 14.0.1 may contain concurrency bugs because the Swift 5.7 compiler can generate invalid code when targeting the macOS 12.3 SDK. If you distribute Mac apps, you should build them with Xcode 13.4.1 until Xcode 14.1 is released. Here’s what happened: Swift 5.7 implements SE-0338: Clarify the Execution of Non-Actor-Isolated Async Functions, which introduces…
11 Oct 2022
SwiftUI’s .task modifier inherits its actor context from the surrounding function. If you call .task inside a view’s body property, the async operation will run on the main actor because View.body is (semi-secretly) annotated with @MainActor. However, if you call .task from a helper property or function that isn’t @MainActor-annotated, the async operation will run in the cooperative thread pool.…
3 Aug 2022
iOS 16 beta 4 is the first SDK release that supports Live Activities. A Live Activity is a widget-like view an app can place on your lock screen and update in real time. Examples where this can be useful include live sports scores or train departure times. These are my notes on playing with the API and implementing my first…
5 May 2022
@MainActor is a Swift annotation to coerce a function to always run on the main thread and to enable the compiler to verify this. How does this work? In this article, I’m going to reimplement @MainActor in a slightly simplified form for illustration purposes, mainly to show how little “magic” there is to it. The code of the real implementation…
27 Apr 2022
Here’s a simple AttributedString with some formatting: import Foundation let str = try! AttributedString( markdown: "Café **Sol**", options: .init(interpretedSyntax: .inlineOnly) ) AttributedString is Codable. If your task was to design the encoding format for an attributed string, what would you come up with? Something like this seems reasonable (in JSON with comments): { "text": "Café Sol", "runs": [ { //…
19 Apr 2022
The environment in SwiftUI is sort of like a global dictionary but with stronger types: each key (represented by a key path) can have its own specific value type. For example, the \.isEnabled key stores a boolean value, whereas the \.font key stores an Optional<Font>. I wrote a custom dictionary type that can do the same thing. The HeterogeneousDictionary struct…
28 Mar 2022
We released the fifth edition of our book Advanced Swift a few days ago. You can buy the ebook on the objc.io site. The hardcover print edition is printed and sold by Amazon (amazon.com, amazon.co.uk, amazon.de). Highlights of the new edition: Fully updated for Swift 5.6 A new Concurrency chapter covering async/await, structured concurrency, and actors New content on property…