RSSAmplifier

Blog

Ole Begemann

oleb.netRSS feed ↗20 posts

Latest posts

Use 'git mv' to record filename case changes in Git

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 refer to the same file (and…

Tracking renamed files in Git

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 is 90 % identical to A’s previous contents, so A was probably…

Building with nightly Swift toolchains on macOS

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 a .pkg installer that installs itself into…

How the Swift compiler knows that DispatchQueue.main implies @MainActor

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…

How the relative size modifier interacts with stack views

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 you’ll also learn some general tidbits about SwiftUI’s layout algorithm…

Working with percentages in SwiftUI layout

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: The chat bubbles should become 80 % as wide as their…

Keyboard shortcuts for Export Unmodified Original in Photos for Mac

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 selected: Export Unmodified…

Swift Evolution proposals in Alfred

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 Lorentey’s…

Pattern matching on error codes

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 = URL ( filePath : "/abc" ) // non-existent…

You should watch Double Fine Adventure

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 and 2015. Broken Age is a beautiful…

Understanding SwiftUI view lifecycles

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 write SwiftUI code, we construct a view tree that consists of nested…

clipped() doesn’t affect hit testing

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 border around the outer frame to visualize the…

When .animation animates more (or less) than it’s supposed to

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 to. This should…

Xcode 14.0 generates wrong concurrency code for macOS targets

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 new…

Where View.task gets its main-actor isolation from

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.…

Experimenting with Live Activities

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 Live Activity. A bike computer on your lock screen My Live Activity is a…

How @MainActor works

@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 in the Swift standard library is available in the…

AttributedString’s Codable format and what it has to do with Unicode

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" :…

A heterogeneous dictionary with strong types in Swift

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 I show in this article stores…

Advanced Swift, fifth edition

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 wrappers, result…