# Ole Begemann

Published articles for Ole Begemann.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

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

DevFeed: [Use 'git mv' to record filename case changes in Git](<https://devfeed.tech/articles/use-git-mv-to-record-filename-case-changes-in-git-21727.md>)

Original publisher: [Read original article](<https://oleb.net/2025/git-mv-case-change/>)

Author: Ole Begemann

Published: 2025-12-16T17:11:22Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Git](<https://devfeed.tech/topics/git.md>), [Filesystems](<https://devfeed.tech/topics/filesystems.md>), [macOS](<https://devfeed.tech/topics/macos.md>), [Windows](<https://devfeed.tech/topics/windows.md>)

Tags: [files](<https://devfeed.tech/tags/files.md>), [git](<https://devfeed.tech/tags/git.md>), [git-commit](<https://devfeed.tech/tags/git-commit.md>), [macos](<https://devfeed.tech/tags/macos.md>), [windows](<https://devfeed.tech/tags/windows.md>)

### AI overview

This tutorial explains that case-only filename changes may not be recorded by Git on case-insensitive, case-preserving filesystems such as default macOS APFS. It demonstrates how using git mv records the new casing correctly and prevents filename mismatches in clones and case-sensitive environments.

### Source excerpt

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 these two cannot coexist in the same directory), but the file system records the filename exactly as you entered it. If you're on a such a file system and change the case of a filename, Git will not record the new name -- unless you use git mv to perform the renaming. Demo 1. Without git mv (bad) Note: I tested this on macOS with the default APFS (case-insensitive) file system. You'll get different results if your file system is case-sensitive. Let's create a fresh repository and commit a single file named A.txt: mkdir testrepo cd testrepo git init echo "Hello" > A.txt git add . git commit -m "Create A" [main (root-commit) 3d73aea] Create A 1 file changed, 1 insertion(+) create mode 100644 A.txt Now we rename the file from A.txt to a.txt: # Rename the file (change case) # Note: not using `git mv` mv A.txt a.txt git status nothing to commit, working tree clean That's interesting. git status says "nothing to commit" because nothing has changed from its perspective. Git is still tracking a file named A.txt, whose contents haven't changed. If we now make edits to the file a.txt (aka A.txt; both names refer to the same file), Git tracks this as a change of the existing file, which is still named A.txt in Git's datastore: echo "World" > a.txt git status Changes not staged for commit: modified: A.txt Let's commit the change: git add . git commit -m "Edit A" [main e86bcb2] Edit A 1 file changed, 1 insertion(+), 1 deletion(-) Now we're in a situation where the recorded filenames on the file system and in Git have diverged. A fresh clone of the repository will create the file with its orig

## Tracking renamed files in Git

DevFeed: [Tracking renamed files in Git](<https://devfeed.tech/articles/tracking-renamed-files-in-git-21726.md>)

Original publisher: [Read original article](<https://oleb.net/2025/git-file-renaming/>)

Author: Ole Begemann

Published: 2025-12-15T15:51:35Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Git](<https://devfeed.tech/topics/git.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [git](<https://devfeed.tech/tags/git.md>), [structure](<https://devfeed.tech/tags/structure.md>)

### AI overview

The article explains that Git stores repository snapshots rather than explicit file-rename records. During diffing, Git uses customizable similarity heuristics to infer likely renames. It recommends making file renames in a standalone commit, separate from substantial content edits, to improve identity tracking.

### Source excerpt

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 renamed to B." This behavior is very much by design: Git FAQ: Why does Git not "track" renames? Linus Torvald's explanation why Git doesn't track renames (2005-04-15) (archived copy) Linus Torvald's email is worth reading. It's well-reasoned and I agree with his arguments: Tracking renames is a superficial solution that fixes only part of the actual problem: how do you track the history of a particular piece of information, which may be much smaller (a single line) or larger (the design of an entire subsystem) than a file, depending on context. Shifting the task of history tracking from commit time to search time allows the search algorithm to do a much better job, because it can be tweaked to the structure of the underlying data. And yet, I still miss the ability to explicitly register a rename operation with Git. Maybe this is because the history tracking tools we have are not as good as what Linus Torvalds envisioned in 2005. Or because sometimes the file is a good enough unit of granularity for history tracking, even if imperfect. Use a separate commit for the rename Git's heuristics work great if renaming a file is all you do in a commit. Tracking only becomes a problem if the renaming coincides with substantial changes to the file's contents in the same commit. Unfortunately, this happens very frequently in my experience: more often than not, my reason for renaming a file is that I made substantial edits and now the filename no longer represents the file's contents. The golden rule: To track a file's identity across renames, perform the rename in a standalone commit, sepa

## Building with nightly Swift toolchains on macOS

DevFeed: [Building with nightly Swift toolchains on macOS](<https://devfeed.tech/articles/building-with-nightly-swift-toolchains-on-macos-21725.md>)

Original publisher: [Read original article](<https://oleb.net/2024/swift-toolchains/>)

Author: Ole Begemann

Published: 2024-03-05T18:54:44Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [toolchains](<https://devfeed.tech/topics/toolchains.md>), [macOS](<https://devfeed.tech/topics/macos.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>), [Xcode](<https://devfeed.tech/topics/xcode.md>), [Package manager](<https://devfeed.tech/topics/package-manager.md>)

Tags: [command-line](<https://devfeed.tech/tags/command-line.md>), [macos](<https://devfeed.tech/tags/macos.md>), [swift](<https://devfeed.tech/tags/swift.md>), [swift-package-manager](<https://devfeed.tech/tags/swift-package-manager.md>), [toolchains](<https://devfeed.tech/tags/toolchains.md>), [xcode](<https://devfeed.tech/tags/xcode.md>)

### AI overview

A practical guide to installing and selecting nightly Swift compiler toolchains on macOS. It covers using custom toolchains in Xcode and from the command line, including the TOOLCHAINS environment variable and bundle IDs. The article also notes limitations such as unsupported playgrounds, built-in Swift Package Manager behavior, and App Store submission restrictions.

### Source excerpt

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 /Library/Developer/Toolchains (or the equivalent path in your home directory). After installation, you have several options to select the toolchain you want to build with: In Xcode In Xcode, select the toolchain from the main menu (Xcode > Toolchains), then build and/or run your code normally. Not all Xcode features work with a custom toolchain. For example, playgrounds don't work, and Xcode will always use its built-in copy of the Swift Package Manager, so you won't be able to use unreleased SwiftPM features in this way. Also, Apple won't accept apps built with a non-standard toolchain for submission to the App Store. On the command line When building on the command line there are multiple options, depending on your preferences and what tool you want to use. The TOOLCHAINS environment variable All of the various Swift build tools respect the TOOLCHAINS environment variable. This should be set to the desired toolchain's bundle ID, which you can find in the Info.plist file in the toolchain's directory. Example (I'm using a nightly toolchain from 2024-03-03 here): # My normal Swift version is 5.10 $ swift --version swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4) # Make sure xcode-select points to Xcode, not to /Library/Developer/CommandLineTools # The Command Line Tools will ignore the TOOLCHAINS variable. $ xcode-select --print-path /Applications/Xcode.app/Contents/Developer # The nightly toolchain is 6.0-dev $ export TOOLCHAINS=org.swift.59202403031a $ swift --version Apple Swift version 6.0-dev (LLVM 0c7823cab15dec9, Swift 0cc0590933

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

DevFeed: [How the Swift compiler knows that DispatchQueue.main implies @MainActor](<https://devfeed.tech/articles/how-the-swift-compiler-knows-that-dispatchqueue-main-implies-mainactor-21724.md>)

Original publisher: [Read original article](<https://oleb.net/2024/dispatchqueue-mainactor/>)

Author: Ole Begemann

Published: 2024-02-29T18:54:47Z

Content type: article

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Xcode](<https://devfeed.tech/topics/xcode.md>)

Tags: [actor](<https://devfeed.tech/tags/actor.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [dispatchqueue](<https://devfeed.tech/tags/dispatchqueue.md>), [swift](<https://devfeed.tech/tags/swift.md>), [xcode](<https://devfeed.tech/tags/xcode.md>)

### AI overview

The article explains that Swift treats closures passed to exactly spelled DispatchQueue.main.async calls as @MainActor-isolated. It reports that this behavior comes from a coarse syntax-based check in the compiler's semantic analysis rather than an annotation on the method, and notes that equivalent expressions using aliases or variables do not receive the same inference.

### Source excerpt

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 welcome and very convenient, but it bugs me that it's so hidden. As far as I know it isn't documented, and neither Xcode nor any other editor/IDE I've used do a good job of showing me the actor context a function or closure will run in, even though the compiler has this information. I've written about a similar case before in Where View.task gets its main-actor isolation from, where Swift/Xcode hide essential information from the programmer by not showing certain attributes in declarations or the documentation. It's a syntax check So how is the magic behavior for DispatchQueue.main.async implemented? It can't be an attribute or other annotation on the closure parameter of the DispatchQueue.async method because the actual queue instance isn't known at that point. A bit of experimentation reveals that it is in fact a relatively coarse source-code-based check that singles out invocations on DispatchQueue.main, in exactly that spelling. For example, the following variations do produce warnings/errors (in Swift 5.10/6.0, respectively), even though they are just as safe as the previous code snippet. This is because we aren't using the "correct" DispatchQueue.main.async spelling: let queue = DispatchQueue.main queue.async { // Error: Call to main actor-isolated global function // 'mainActorFunc()' in a synchronous nonisolated context mainActorFunc() // ❌ } typealias DP = DispatchQueue DP.main.async { // Error: Call to main actor-isolated global function // 'mainActorFunc()' in a synchronous nonisolated context mainActorFunc() // ❌ } I found the place in the Swift compiler source code

## How the relative size modifier interacts with stack views

DevFeed: [How the relative size modifier interacts with stack views](<https://devfeed.tech/articles/how-the-relative-size-modifier-interacts-with-stack-views-21722.md>)

Original publisher: [Read original article](<https://oleb.net/2023/swiftui-relative-size-in-stacks/>)

Author: Ole Begemann

Published: 2023-03-24T20:14:49Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [code](<https://devfeed.tech/tags/code.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>)

### AI overview

The article explains how a relative sizing modifier behaves when applied to views inside SwiftUI HStacks. Because the stack proposes space to children sequentially, the modifier can produce uneven widths depending on which child uses it. It also notes that SwiftUI's built-in containerRelativeFrame modifier behaves differently.

### Source excerpt

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 for HStacks and VStacks. Using relative sizing inside a stack view Let's apply the relativeProposed modifier to one of the subviews of an HStack: HStack(spacing: 10) { Color.blue .relativeProposed(width: 0.5) Color.green Color.yellow } .border(.primary) .frame(height: 80) What do you expect to happen here? Will the blue view take up 50 % of the available width? The answer is no. In fact, the blue rectangle becomes narrower than the others: This is because the HStack only proposes a proportion of its available width to each of its children. Here, the stack proposes one third of the available space to its first child, the relative sizing modifier. The modifier then halves this value, resulting in one sixth of the total width (minus spacing) for the blue color. The other two rectangles then become wider than one third because the first child view didn't use up its full proposed width. Update May 1, 2024: SwiftUI's built-in containerRelativeFrame modifier (introduced after I wrote my modifier) doesn't exhibit this behavior because it uses the size of the nearest container view as its reference, and stack views don't count as containers in this context (which I find somewhat unintuitive, but that's the way it is). Order matters Now let's move the modifier to the green color in the middle: HStack(spacing: 10) { Color.blue Color.green .relativeProposed(width: 0.5) Color.yellow } Naively, I'd expect an equivalent result: the green rectangle should become 100 pt wide, and blue and yellow should be 250 pt each. But that's not what happens -- the yellow view ends up being wider than the

## Working with percentages in SwiftUI layout

DevFeed: [Working with percentages in SwiftUI layout](<https://devfeed.tech/articles/working-with-percentages-in-swiftui-layout-21723.md>)

Original publisher: [Read original article](<https://oleb.net/2023/swiftui-relative-size/>)

Author: Ole Begemann

Published: 2023-03-23T22:31:11Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [build](<https://devfeed.tech/tags/build.md>), [code](<https://devfeed.tech/tags/code.md>), [layout](<https://devfeed.tech/tags/layout.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>)

### AI overview

A tutorial on implementing relative sizing in SwiftUI by creating a custom Layout-based modifier. The modifier scales the proposed width and height before passing them to a single subview, with examples using chat bubbles and maximum-width constraints.

### Source excerpt

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 container. Download video Building a proportional sizing modifier 1. The Layout We can build our own relative sizing modifier on top of the Layout protocol. The layout multiplies its own proposed size (which it receives from its parent view) with the given factors for width and height. It then proposes this modified size to its only subview. Here's the implementation (the full code, including the demo app, is on GitHub): /// A custom layout that proposes a percentage of its /// received proposed size to its subview. /// /// - Precondition: must contain exactly one subview. fileprivate struct RelativeSizeLayout: Layout { var relativeWidth: Double var relativeHeight: Double func sizeThatFits( proposal: ProposedViewSize, subviews: Subviews, cache: inout () ) -> CGSize { assert(subviews.count == 1, "expects a single subview") let resizedProposal = ProposedViewSize( width: proposal.width.map { $0 * relativeWidth }, height: proposal.height.map { $0 * relativeHeight } ) return subviews[0].sizeThatFits(resizedProposal) } func placeSubviews( in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () ) { assert(subviews.count == 1, "expects a single subview") let resizedProposal = ProposedViewSize( width: proposal.width.map { $0 * relativeWidth }, height: proposal.height.map { $0 * relativeHeight } ) subviews[0].place( at: CGPoint(x: bounds.midX, y: bounds.midY), anchor: .center, proposal: resizedProposal ) } } Notes: I made the type private because I want to control how it can be used. This is important for maintaining the assumption that the layout only ever has

## Keyboard shortcuts for Export Unmodified Original in Photos for Mac

DevFeed: [Keyboard shortcuts for Export Unmodified Original in Photos for Mac](<https://devfeed.tech/articles/keyboard-shortcuts-for-export-unmodified-original-in-photos-for-mac-21721.md>)

Original publisher: [Read original article](<https://oleb.net/2023/photos-keyboard-shortcuts/>)

Author: Ole Begemann

Published: 2023-03-21T21:42:04Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [macOS](<https://devfeed.tech/topics/macos.md>), [Scripting, bash](<https://devfeed.tech/topics/scripting-bash.md>), [Script](<https://devfeed.tech/topics/script.md>)

Tags: [bash](<https://devfeed.tech/tags/bash.md>), [commands](<https://devfeed.tech/tags/commands.md>), [keyboard](<https://devfeed.tech/tags/keyboard.md>), [mac](<https://devfeed.tech/tags/mac.md>), [script](<https://devfeed.tech/tags/script.md>), [shortcuts](<https://devfeed.tech/tags/shortcuts.md>)

### AI overview

This tutorial explains how to assign a keyboard shortcut to Photos.app's Export Unmodified Original command on macOS. It provides a Bash script that configures the shortcut for selections of up to 20 photos, videos, or mixed items, and notes a macOS 13.2 bug requiring the relevant menu to be opened once first.

### Source excerpt

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 Original For 1 Photo" turns into "... Originals For 2 Videos" turns into "... For 3 Items" (for mixed selections), and so on. Argh! The System Settings UI for assigning keyboard shortcuts is extremely tedious to use if you want to add more than one or two shortcuts. Dynamically renaming menu commands is cute, but it becomes a problem when you want to assign keyboard shortcuts. Solution: shell script Here's a Bash script1 that assigns Ctrl + Opt + Cmd + E to Export Unmodified Originals for up to 20 selected items: #!/bin/bash # Assigns a keyboard shortcut to the Export Unmodified Originals # menu command in Photos.app on macOS. # @ = Command # ^ = Control # ~ = Option # $ = Shift shortcut='@~^e' # Set shortcut for 1 selected item echo "Setting shortcut for 1 item" defaults write com.apple.Photos NSUserKeyEquivalents -dict-add "Export Unmodified Original For 1 Photo" "$shortcut" defaults write com.apple.Photos NSUserKeyEquivalents -dict-add "Export Unmodified Original For 1 Video" "$shortcut" # Set shortcut for 2-20 selected items objects=(Photos Videos Items) for i in {2..20} do echo "Setting shortcut for $i items" for object in "${objects[@]}" do defaults write com.apple.Photos NSUserKeyEquivalents -dict-add "Export Unmodified Originals For $i $object" "$shortcut" done done # Use this command to verify the result: # defaults read com.apple.Photos NSUserKeyEquivalents The script is also available on GitHub. Usage: Quit Photos.app. Run the script. Feel free to change the key combo or count higher than 20. Open Photos.app. Note: There's a bug in Photos.app on macOS 13.2 (and at least s

## Swift Evolution proposals in Alfred

DevFeed: [Swift Evolution proposals in Alfred](<https://devfeed.tech/articles/swift-evolution-proposals-in-alfred-21718.md>)

Original publisher: [Read original article](<https://oleb.net/2023/alfred-swift-evolution/>)

Author: Ole Begemann

Published: 2023-03-09T22:33:14Z

Content type: release

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Tool](<https://devfeed.tech/topics/tool.md>), [Script](<https://devfeed.tech/topics/script.md>)

Tags: [download](<https://devfeed.tech/tags/download.md>), [evolution](<https://devfeed.tech/tags/evolution.md>), [github](<https://devfeed.tech/tags/github.md>), [improvements](<https://devfeed.tech/tags/improvements.md>), [markdown](<https://devfeed.tech/tags/markdown.md>), [script](<https://devfeed.tech/tags/script.md>), [swift](<https://devfeed.tech/tags/swift.md>), [tool](<https://devfeed.tech/tags/tool.md>), [update](<https://devfeed.tech/tags/update.md>), [workflow](<https://devfeed.tech/tags/workflow.md>)

### AI overview

The article announces version 2.1.0 of Karoy Lorentey's swift-evolution workflow for Alfred. The update fixes a break caused by Swift Evolution data format changes and adds improved proposal-title display, copy actions, and metadata variables for custom actions.

### Source excerpt

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 swift-evolution workflow for Alfred. The workflow broke recently due to data format changes. Karoy was kind enough to add me as a maintainer so I could fix it. The new version 2.1.0 is now available on GitHub. Download the .alfredworkflow file and double-click to install. Besides the fix, the update has a few other improvements: The proposal title is now displayed more prominently. New actions to copy the proposal title (hold down Command) or copy it as a Markdown link (hold down Shift + Command). The script forwards the main metadata of the selected proposal (id, title, status, URL) to Alfred. If you want to extend the workflow with your own actions, you can refer to these variables.

## Pattern matching on error codes

DevFeed: [Pattern matching on error codes](<https://devfeed.tech/articles/pattern-matching-on-error-codes-21719.md>)

Original publisher: [Read original article](<https://oleb.net/2023/catch-error-code/>)

Author: Ole Begemann

Published: 2023-02-27T19:32:22Z

Content type: article

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Code](<https://devfeed.tech/topics/code.md>), [Framework](<https://devfeed.tech/topics/framework.md>)

Tags: [apple](<https://devfeed.tech/tags/apple.md>), [code](<https://devfeed.tech/tags/code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [operator](<https://devfeed.tech/tags/operator.md>), [pattern-matching](<https://devfeed.tech/tags/pattern-matching.md>), [protocol](<https://devfeed.tech/tags/protocol.md>), [swift](<https://devfeed.tech/tags/swift.md>), [syntax](<https://devfeed.tech/tags/syntax.md>)

### AI overview

This article explains why Swift allows concise pattern matching against Foundation error codes. Foundation overloads the ~= operator to compare error values with error codes, rather than relying on special compiler behavior. The technique applies to CocoaError, URLError, POSIXError, and MachError.

### Source excerpt

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 file let data = try Data(contentsOf: fileURL) } catch let error as CocoaError where error.code == .fileReadNoSuchFile { print("File doesn't exist") } catch { print("Other error: \(error)") } This binds a value of type CocoaError to the variable error and then uses a where clause to check the specific error code. However, if you don't need access to the complete error instance, there's a shorter way to write this, matching directly against the error code: let data = try Data(contentsOf: fileURL) - } catch let error as CocoaError where error.code == .fileReadNoSuchFile { + } catch CocoaError.fileReadNoSuchFile { print("File doesn't exist") Foundation overloads ~= I was wondering why this shorter syntax works. Is there some special compiler magic for pattern matching against error codes of NSError instances? Turns out: no, the answer is much simpler. Foundation includes an overload for the pattern matching operator ~= that matches error values against error codes.1 The implementation looks something like this: public func ~= (code: CocoaError.Code, error: any Error) -> Bool { guard let error = error as? CocoaError else { return false } return error.code == code } The actual code in Foundation is a little more complex because it goes through a hidden protocol named _ErrorCodeProtocol, but that's not important. You can check out the code in the Foundation repository: Darwin version, swift-corelibs-foundation version. This matching on error codes is available for CocoaError, URLError, POSIXError, and MachError (and possibly more types in other Apple frameworks, I haven't checked). I w

## Double Fine Adventure documents the development of Broken Age

DevFeed: [Double Fine Adventure documents the development of Broken Age](<https://devfeed.tech/articles/you-should-watch-double-fine-adventure-21720.md>)

Original publisher: [Read original article](<https://oleb.net/2023/double-fine-adventure/>)

Author: Ole Begemann

Published: 2023-01-31T18:39:27Z

Content type: opinion

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Development](<https://devfeed.tech/topics/development.md>), [Process](<https://devfeed.tech/topics/process.md>)

Tags: [development](<https://devfeed.tech/tags/development.md>), [development-process](<https://devfeed.tech/tags/development-process.md>), [experience](<https://devfeed.tech/tags/experience.md>), [financial](<https://devfeed.tech/tags/financial.md>), [kickstarter](<https://devfeed.tech/tags/kickstarter.md>), [people](<https://devfeed.tech/tags/people.md>), [platforms](<https://devfeed.tech/tags/platforms.md>), [play](<https://devfeed.tech/tags/play.md>), [production](<https://devfeed.tech/tags/production.md>), [project](<https://devfeed.tech/tags/project.md>), [team](<https://devfeed.tech/tags/team.md>), [video](<https://devfeed.tech/tags/video.md>), [work](<https://devfeed.tech/tags/work.md>), [youtube](<https://devfeed.tech/tags/youtube.md>)

### AI overview

This opinion article recommends the Double Fine Adventure documentary, which follows the three-year development of Broken Age and offers candid insight into game development, including financial problems, layoffs, and long work hours. It also discusses experiencing the documentary alongside the game.

### Source excerpt

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 game and I recommend you try it. It's available for lots of platforms and is pretty cheap (10-15 euros/dollars or less). I played it on the Nintendo Switch, which worked very well. Broken Age. But the real gem to me was watching the 12.5-hour documentary on YouTube. A video production team followed the entire three-year development process from start to finish. It provides a refreshingly candid and transparent insight into "how the sausage is made", including sensitive topics such as financial problems, layoffs, and long work hours. Throughout all the ups and downs there's a wonderful sense of fun and camaraderie among the team at Double Fine, which made watching the documentary even more enjoyable to me than playing Broken Age. You can tell these people love working with each other. I highly recommend taking a look if you find this mildly interesting. The Double Fine Adventure documentary. The first major game spoilers don't come until episode 15, so you can safely watch most of the documentary before playing the game (and this is how the original Kickstarter backers experienced it). However, I think it's even more interesting to play the game first, or to experience both side-by-side. My suggestion: watch two or three episodes of the documentary. If you like it, start playing Broken Age alongside it.

## Understanding SwiftUI view lifecycles

DevFeed: [Understanding SwiftUI view lifecycles](<https://devfeed.tech/articles/understanding-swiftui-view-lifecycles-21716.md>)

Original publisher: [Read original article](<https://oleb.net/2022/swiftui-view-lifecycle/>)

Author: Ole Begemann

Published: 2022-12-15T20:52:46Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [App](<https://devfeed.tech/topics/app.md>), [Code](<https://devfeed.tech/topics/code.md>), [iOS](<https://devfeed.tech/topics/ios.md>), [macOS](<https://devfeed.tech/topics/macos.md>)

Tags: [app](<https://devfeed.tech/tags/app.md>), [code](<https://devfeed.tech/tags/code.md>), [examples](<https://devfeed.tech/tags/examples.md>), [ios](<https://devfeed.tech/tags/ios.md>), [lifecycle](<https://devfeed.tech/tags/lifecycle.md>), [macos](<https://devfeed.tech/tags/macos.md>), [render](<https://devfeed.tech/tags/render.md>), [screen](<https://devfeed.tech/tags/screen.md>), [state](<https://devfeed.tech/tags/state.md>), [stateobject](<https://devfeed.tech/tags/stateobject.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>), [view](<https://devfeed.tech/tags/view.md>)

### AI overview

This article explains how SwiftUI view and render trees affect view identity, lifecycle, and state. It describes how state changes can recreate view values while render-tree objects persist, and presents the SwiftUI View Lifecycle app as a way to observe lifecycle events.

### Source excerpt

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 view values. Instances of the view tree are ephemeral: SwiftUI constantly destroys and recreates (parts of) the view tree as it processes state changes. The view tree serves as a blueprint from which SwiftUI creates a second tree, which represents the actual view "objects" that are "on screen" at any given time (the "objects" could be actual UIView or NSView objects, but also other representations; the exact meaning of "on screen" can vary depending on context). Chris Eidhof likes to call this second tree the render tree (the link points to a 3 minute video where Chris demonstrates this duality, highly recommended). The render tree persists across state changes and is used by SwiftUI to establish view identity. When a state change causes a change in a view's value, SwiftUI will find the corresponding view object in the render tree and update it in place, rather than recreating a new view object from scratch. This is of course key to making SwiftUI efficient, but the render tree has another important function: it controls the lifetimes of views and their state. View lifecycles and state We can define a view's lifetime as the timespan it exists in the render tree. The lifetime begins with the insertion into the render tree and ends with the removal. Importantly, the lifetime extends to view state defined with @State and @StateObject: when a view gets removed from the render tree, its state is lost; when the view gets inserted again later, the state will be recreated with its initial value. The SwiftUI View Lifecycle app tracks three lifecycle events for a view and displays the

## clipped() doesn't affect hit testing

DevFeed: [clipped() doesn't affect hit testing](<https://devfeed.tech/articles/clipped-doesn-t-affect-hit-testing-21711.md>)

Original publisher: [Read original article](<https://oleb.net/2022/clipped-hit-testing/>)

Author: Ole Begemann

Published: 2022-11-24T18:30:58Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [iOS](<https://devfeed.tech/topics/ios.md>), [macOS](<https://devfeed.tech/topics/macos.md>), [ui](<https://devfeed.tech/topics/ui.md>)

Tags: [ios](<https://devfeed.tech/tags/ios.md>), [macos](<https://devfeed.tech/tags/macos.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

A SwiftUI tutorial explains that clipping a view with clipped() does not limit its hit-testing region. Using contentShape(Rectangle()) on the constrained frame limits hit testing to the visible area, allowing an obscured button to receive taps. The behavior was tested on iOS 16.1 and macOS 13.0.

### Source excerpt

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 300x300 square, which we then constrain to a 100x100 frame. I also added a border around the outer frame to visualize the views: Rectangle() .fill(.orange.gradient) .frame(width: 300, height: 300) // Set view to 100x100 -> renders out of bounds .frame(width: 100, height: 100) .border(.blue) SwiftUI views don't clip their content by default, hence the full 300x300 square remains visible. Notice the blue border that indicates the 100x100 outer frame: Now let's add .clipped() to clip the large square to the 100x100 frame. I also made the square tappable and added a button: VStack { Button("You can't tap me!") { buttonTapCount += 1 } .buttonStyle(.borderedProminent) Rectangle() .fill(.orange.gradient) .frame(width: 300, height: 300) .frame(width: 100, height: 100) .clipped() .onTapGesture { rectTapCount += 1 } } When you run this code, you'll discover that the button isn't tappable at all. This is because the (unclipped) square, despite not being fully visible, obscures the button and "steals" all taps. The dashed outline indicates the hit area of the orange square. The button isn't tappable because it's covered by the clipped view with respect to hit testing. The fix: .contentShape() The contentShape(_:) modifier defines the hit testing area for a view. By adding .contentShape(Rectangle()) to the 100x100 frame, we limit hit testing to that area, making the button tappable again: Rectangle() .fill(.orange.gradient) .frame(width: 300, height: 300) .frame(width: 100, height: 100) .contentShape(Rectangle()) .clipped() Note that the order of .contentShape(Rectangle()) and .clipped() could be swapped. The important thing is that contentShape is an (indirect) parent of the 100x100 frame modifier that de

## How SwiftUI's .animation Modifier Applies Animations in the View Tree

DevFeed: [How SwiftUI's .animation Modifier Applies Animations in the View Tree](<https://devfeed.tech/articles/when-animation-animates-more-or-less-than-it-s-supposed-to-21709.md>)

Original publisher: [Read original article](<https://oleb.net/2022/animation-modifier-position/>)

Author: Ole Begemann

Published: 2022-11-10T21:48:45Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [iOS](<https://devfeed.tech/topics/ios.md>), [macOS](<https://devfeed.tech/topics/macos.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [animation](<https://devfeed.tech/tags/animation.md>), [ios](<https://devfeed.tech/tags/ios.md>), [macos](<https://devfeed.tech/tags/macos.md>), [snippet](<https://devfeed.tech/tags/snippet.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>)

### AI overview

This article examines how SwiftUI's .animation modifier behaves within the view tree. It explains that sibling subtrees can use different animations, nested modifiers can override outer animations, and the modifier generally affects subviews with some exceptions.

### Source excerpt

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 give us complete control over which modifiers we want to animate, right? Unfortunately, it's not that simple: it's easy to run into situations where a view change inside an animated subtree doesn't get animated, or vice versa. Unsurprising examples Let me give you some examples, starting with those that do work as documented. I tested all examples on iOS 16.1 and macOS 13.0. 1. Sibling views can have different animations Independent subtrees of the view tree can be animated independently. In this example we have three sibling views, two of which are animated with different durations, and one that isn't animated at all: struct Example1: View { var flag: Bool var body: some View { HStack(spacing: 40) { Rectangle() .frame(width: 80, height: 80) .foregroundColor(.green) .scaleEffect(flag ? 1 : 1.5) .animation(.easeOut(duration: 0.5), value: flag) Rectangle() .frame(width: 80, height: 80) .foregroundColor(flag ? .yellow : .red) .rotationEffect(flag ? .zero : .degrees(45)) .animation(.easeOut(duration: 2.0), value: flag) Rectangle() .frame(width: 80, height: 80) .foregroundColor(flag ? .pink : .mint) } } } The two animation modifiers each apply to their own subtree. They don't interfere with each other and have no effect on the rest of the view hierarchy: Download video 2. Nested animation modifiers When two animation modifiers are nested in a single view tree such that one is an indirect parent of the other, the inner modifier can override the outer animation for its subviews. The outer animation applies to view modifiers that are placed between the two animation modifiers. In this

## Xcode 14.0 generates wrong concurrency code for macOS targets

DevFeed: [Xcode 14.0 generates wrong concurrency code for macOS targets](<https://devfeed.tech/articles/xcode-14-0-generates-wrong-concurrency-code-for-macos-targets-21717.md>)

Original publisher: [Read original article](<https://oleb.net/2022/xcode-14-mac-concurrency-bugs/>)

Author: Ole Begemann

Published: 2022-10-12T19:12:17Z

Content type: article

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Xcode](<https://devfeed.tech/topics/xcode.md>), [macOS](<https://devfeed.tech/topics/macos.md>), [Swift](<https://devfeed.tech/topics/swift.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [bug](<https://devfeed.tech/topics/bug.md>)

Tags: [bug](<https://devfeed.tech/tags/bug.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [macos](<https://devfeed.tech/tags/macos.md>), [sdk](<https://devfeed.tech/tags/sdk.md>), [swift](<https://devfeed.tech/tags/swift.md>), [xcode](<https://devfeed.tech/tags/xcode.md>)

### AI overview

Xcode 14.0 and 14.0.1 can generate invalid concurrency code for macOS targets because the Swift 5.7 compiler is used with the older macOS 12.3 SDK and its Swift 5.6 standard library. The article recommends building with Xcode 13.4.1 until Xcode 14.1, which includes the macOS 13 SDK, is released.

### Source excerpt

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 rules how async functions hop between executors. Because of SE-0338, when compiling concurrency code, the Swift 5.7 compiler places executor hops in different places than Swift 5.6. Some standard library functions need to opt out of the new rules. They are annotated with a new, unofficial attribute @_unsafeInheritExecutor, which was introduced for this purpose. When the Swift 5.7 compiler sees this attribute, it generates different executor hops. The attribute is only present in the Swift 5.7 standard library, i.e. in the iOS 16 and macOS 13 SDKs. This is fine for iOS because compiler version and the SDK's standard library version match in Xcode 14.0. But for macOS targets, Xcode 14.0 uses the Swift 5.7 compiler with the standard library from Swift 5.6, which doesn't contain the @_unsafeInheritExecutor attribute. This is what causes the bugs. Note that the issue is caused purely by the version mismatch at compile-time. The standard library version used by the compiled app at run-time (which depends on the OS version the app runs on) isn't relevant. As soon as Xcode 14.1 gets released with the macOS 13 SDK, the version mismatch will go away, and Mac targets built with Xcode 14.1 won't exhibit these bugs. Third-party developers had little chance of discovering the bug during the Xcode 14.0 beta phase because the betas ship with the new beta macOS SDK. The version mismatch occurs when the final Xcode release in September reverts back to the old macOS SDK to accommodate the different release schedules of iOS and macOS. Sources Breaking concurrency invariants is a serious issue, thou

## Where View.task gets its main-actor isolation from

DevFeed: [Where View.task gets its main-actor isolation from](<https://devfeed.tech/articles/where-view-task-gets-its-main-actor-isolation-from-21715.md>)

Original publisher: [Read original article](<https://oleb.net/2022/swiftui-task-mainactor/>)

Author: Ole Begemann

Published: 2022-10-11T16:41:34Z

Content type: article

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [Swift](<https://devfeed.tech/topics/swift.md>), [context](<https://devfeed.tech/topics/context.md>), [interfaces](<https://devfeed.tech/topics/interfaces.md>), [modules](<https://devfeed.tech/topics/modules.md>)

Tags: [context](<https://devfeed.tech/tags/context.md>), [interfaces](<https://devfeed.tech/tags/interfaces.md>), [modules](<https://devfeed.tech/tags/modules.md>), [swift](<https://devfeed.tech/tags/swift.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>)

### AI overview

This article explains how SwiftUI's .task modifier inherits actor context from its use site. Calls inside a View body run on the main actor because View.body is annotated with @MainActor, while calls from nonisolated helper properties or functions run in the cooperative thread pool. It examines SwiftUI's hidden annotations and module interface declarations to explain the behavior.

### Source excerpt

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. Example Here's an example. Notice the two .task modifiers in body and helperView. The code is identical in both, yet only one of them compiles -- in helperView, the call to a main-actor-isolated function fails because we're not on the main actor in that context: We can call a main-actor-isolated function from inside body, but not from a helper property. import SwiftUI @MainActor func onMainActor() { print("on MainActor") } struct ContentView: View { var body: some View { VStack { helperView Text("in body") .task { // We can call a @MainActor func without await onMainActor() } } } var helperView: some View { Text("in helperView") .task { // ❗ Error: Expression is 'async' but is not marked with 'await' onMainActor() } } } Why does it work like this? This behavior is caused by two (semi-)hidden annotations in the SwiftUI framework: The View protocol annotates its body property with @MainActor. This transfers to all conforming types. View.task annotates its action parameter with @_inheritActorContext, causing it to adopt the actor context from its use site. Sadly, none of these annotations are visible in the SwiftUI documentation, making it very difficult to understand what's going on. The @MainActor annotation on View.body is present in Xcode's generated Swift interface for SwiftUI (Jump to Definition of View), but that feature doesn't work reliably for me, and as we'll see, it doesn't show the whole truth, either. View.body is annotated with @MainActor in Xcode's generated interface for SwiftUI. SwiftUI's module interface To really see the declarations the compiler sees, we ne

## Experimenting with Live Activities

DevFeed: [Experimenting with Live Activities](<https://devfeed.tech/articles/experimenting-with-live-activities-21714.md>)

Original publisher: [Read original article](<https://oleb.net/2022/live-activity/>)

Author: Ole Begemann

Published: 2022-08-03T16:50:39Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [iOS](<https://devfeed.tech/topics/ios.md>), [API](<https://devfeed.tech/topics/api.md>), [real-time](<https://devfeed.tech/topics/real-time.md>), [Bluetooth](<https://devfeed.tech/topics/bluetooth.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [apple](<https://devfeed.tech/tags/apple.md>), [bluetooth](<https://devfeed.tech/tags/bluetooth.md>), [ios](<https://devfeed.tech/tags/ios.md>), [sdk](<https://devfeed.tech/tags/sdk.md>)

### AI overview

An experiment with iOS Live Activities in iOS 16 beta 4, including a bike-computer speedometer use case and observations about starting, updating, and dismissing activities.

### Source excerpt

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 display for a bike computer that I've been developing with a group a friends. Here's a video of it in action: Download video And here with simulated data: Download video I haven't talked much about our bike computer project publicly yet; that will hopefully change someday. In short, a group of friends and I designed a little box that connects to your bike's hub dynamo, measures speed and distance, and sends the data via Bluetooth to an iOS app. The app records all your rides and can also act as a live speedometer when mounted on your bike's handlebar. It's this last feature that I wanted to replicate in the Live Activity. Follow Apple's guide Adding a Live Activity to the app wasn't hard. I found Apple's guide Displaying live data on the Lock Screen with Live Activities easy to follow and quite comprehensive. No explicit user approval iOS doesn't ask the user for approval when an app wants to show a Live Activity. I found this odd since it seems to invite developers to abuse the feature, but maybe it's OK because of the foreground requirement (see below). Plus, users can disallow Live Activities on a per-app basis in Settings. Users can dismiss an active Live Activity from the lock screen by swiping (like a notification). Most apps will probably need to ask the user for notification permissions to update their Live Activities. The app must be in the foreground to start an activity To start a Live Activity, an app must be open in the foreground. This isn't ideal for the bike computer because the speedometer can't appear magically on the lock screen when the user starts riding

## How @MainActor works

DevFeed: [How @MainActor works](<https://devfeed.tech/articles/how-mainactor-works-21713.md>)

Original publisher: [Read original article](<https://oleb.net/2022/how-mainactor-works/>)

Author: Ole Begemann

Published: 2022-05-05T13:52:42Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Protocol (disambiguation)](<https://devfeed.tech/topics/protocol.md>)

Tags: [await](<https://devfeed.tech/tags/await.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [executor](<https://devfeed.tech/tags/executor.md>), [main-thread](<https://devfeed.tech/tags/main-thread.md>), [protocol](<https://devfeed.tech/tags/protocol.md>), [swift](<https://devfeed.tech/tags/swift.md>)

### AI overview

This tutorial explains how Swift's @MainActor works by reimplementing it in simplified form. It describes the roles of global actors and custom executors, including how a custom serial executor can run jobs on the main dispatch queue.

### Source excerpt

@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 Swift repository. @MainActor relies on two Swift features, one of them unofficial: global actors and custom executors. Global actors MainActor is a global actor. That is, it provides a single actor instance that is shared between all places in the code that are annotated with @MainActor. All global actors must implement the shared property that's defined in the GlobalActor protocol (every global actor implicitly conforms to this protocol): @globalActor final actor MyMainActor { // Requirements from the implicit GlobalActor conformance typealias ActorType = MyMainActor static var shared: ActorType = MyMainActor() // Don't allow others to create instances private init() {} } At this point, we have a global actor that has the same semantics as any other actor. That is, functions annotated with @MyMainActor will run on a thread in the cooperative thread pool managed by the Swift runtime. To move the work to the main thread, we need another concept, custom executors. Executors A bit of terminology: The compiler splits async code into jobs. A job roughly corresponds to the code from one await (= potential suspension point) to the next. The runtime submits each job to an executor. The executor is the object that decides in which order and in which context (i.e. which thread or dispatch queue) to run the jobs. Swift ships with two built-in executors: the default concurrent executor, used for "normal", non-actor-isolated async functions, and a default serial executor. Every actor instance has its own instance of this default serial executor and runs its code on it. Since the serial exec

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

DevFeed: [AttributedString's Codable format and what it has to do with Unicode](<https://devfeed.tech/articles/attributedstring-s-codable-format-and-what-it-has-to-do-with-unicode-21710.md>)

Original publisher: [Read original article](<https://oleb.net/2022/attributedstring-codable/>)

Author: Ole Begemann

Published: 2022-04-27T13:28:03Z

Content type: article

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [JSON](<https://devfeed.tech/topics/json.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [json](<https://devfeed.tech/tags/json.md>), [serialization](<https://devfeed.tech/tags/serialization.md>), [swift](<https://devfeed.tech/tags/swift.md>)

### AI overview

The article examines how to encode Swift AttributedString values and explains why character-based or UTF-8 byte-based formatting ranges can become invalid across Unicode versions, Swift versions, operating systems, or normalization changes. It discusses storing UTF-8 bytes as a safer alternative.

### Source excerpt

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": [ { // start..<end in Character offsets "range": [5, 8], "attrs": { "strong": true } } ] } This stores the text alongside an array of runs of formatting attributes. Each run consists of a character range and an attribute dictionary. Unicode is complicated But this format is bad and can break in various ways. The problem is that the character offsets that define the runs aren't guaranteed to be stable. The definition of what constitutes a Character, i.e. a user-perceived character, or a Unicode grapheme cluster, can and does change in new Unicode versions. If we decoded an attributed string that had been serialized on a different OS version (before Swift 5.6, Swift used the OS's Unicode library for determining character boundaries), or by code compiled with a different Swift version (since Swift 5.6, Swift uses its own grapheme breaking algorithm that will be updated alongside the Unicode standard)1, the character ranges might no longer represent the original intent, or even become invalid. Update April 11, 2024: See this Swift forum post I wrote for an example where the Unicode rules for grapheme cluster segmentation changed for flag emoji. This change caused a corresponding change in how Swift counts the Characters in a string containing consecutive flags, such as "🇦🇷🇯🇵". Normalization forms So let's use UTF-8 byte offsets for the ranges, I hear you say. This avoids the first issue but still isn't safe, because some characters, such as the é in the example string, have more than one representation in Unicode: it can be either the standalone character é (Latin small let

## A heterogeneous dictionary with strong types in Swift

DevFeed: [A heterogeneous dictionary with strong types in Swift](<https://devfeed.tech/articles/a-heterogeneous-dictionary-with-strong-types-in-swift-21712.md>)

Original publisher: [Read original article](<https://oleb.net/2022/heterogeneous-dictionary/>)

Author: Ole Begemann

Published: 2022-04-19T15:52:08Z

Content type: tutorial

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [SwiftUI](<https://devfeed.tech/topics/swiftui.md>), [Code](<https://devfeed.tech/topics/code.md>), [Protocol (disambiguation)](<https://devfeed.tech/topics/protocol.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [protocol](<https://devfeed.tech/tags/protocol.md>), [swift](<https://devfeed.tech/tags/swift.md>), [swiftui](<https://devfeed.tech/tags/swiftui.md>)

### AI overview

This article presents a type-safe heterogeneous dictionary in Swift, modeled partly on the SwiftUI environment. Each type-based key is associated with a specific value type, allowing mixed key-value pairs without casting. The design uses domains or keyspaces to restrict which keys belong to a dictionary.

### Source excerpt

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 mixed key-value pairs where each key defines the type of value it stores. The public API is fully type-safe, no casting required. Usage I'll start with an example of the finished API. Here's a dictionary for storing text formatting attributes: import AppKit var dict = HeterogeneousDictionary<TextAttributes>() dict[ForegroundColor.self] // -> nil // The value type of this key is NSColor dict[ForegroundColor.self] = NSColor.systemRed dict[ForegroundColor.self] // -> NSColor.systemRed dict[FontSize.self] // -> nil // The value type of this key is Double dict[FontSize.self] = 24 dict[FontSize.self] // -> 24 (type: Optional<Double>) We also need some boilerplate to define the set of keys and their associated value types. The code to do this for three keys (font, font size, foreground color) looks like this: // The domain (aka "keyspace") enum TextAttributes {} struct FontSize: HeterogeneousDictionaryKey { typealias Domain = TextAttributes typealias Value = Double } struct Font: HeterogeneousDictionaryKey { typealias Domain = TextAttributes typealias Value = NSFont } struct ForegroundColor: HeterogeneousDictionaryKey { typealias Domain = TextAttributes typealias Value = NSColor } Yes, this is fairly long, which is one of the downsides of this approach. At least you only have to write it once per "keyspace". I'll walk you through it step by step. Notes on the API Using types as keys As you can see in this line, the dictionary keys are types (more precisely, metatype values): dict[FontSize.self] = 24 This is another parallel with the SwiftUI environment, which also uses types as keys (the p

## Advanced Swift, fifth edition

DevFeed: [Advanced Swift, fifth edition](<https://devfeed.tech/articles/advanced-swift-fifth-edition-21708.md>)

Original publisher: [Read original article](<https://oleb.net/2022/advanced-swift-5/>)

Author: Ole Begemann

Published: 2022-03-28T14:03:30Z

Content type: release

Language: en

Sources: [Ole Begemann](<https://devfeed.tech/sources/ole-begemann.md>)

Topics: [Swift](<https://devfeed.tech/topics/swift.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [async/await](<https://devfeed.tech/topics/async-await.md>)

Tags: [async](<https://devfeed.tech/tags/async.md>), [await](<https://devfeed.tech/tags/await.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [generics](<https://devfeed.tech/tags/generics.md>), [release](<https://devfeed.tech/tags/release.md>), [structured-concurrency](<https://devfeed.tech/tags/structured-concurrency.md>), [swift](<https://devfeed.tech/tags/swift.md>)

### AI overview

The fifth edition of Advanced Swift has been released. It is updated for Swift 5.6, adds a chapter on concurrency covering async/await, structured concurrency, and actors, and includes new material on property wrappers, result builders, protocols, and generics. The print edition is now a hardcover, and ebook owners receive a free update.

### Source excerpt

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 builders, protocols, and generics The print edition is now a hardcover (for the same price) Free update for owners of the ebook A growing book for a growing language Updating the book always turns out to be more work than I expect. Swift has grown substantially since our last release (for Swift 5.0), and the size of the book reflects this. The fifth edition is 76 % longer than the first edition from 2016. This time, we barely stayed under 1 million characters: Character counts of Advanced Swift editions from 2016-2022. Many thanks to our editor, Natalye, for reading all this and improving our Dutch/German dialect of English. Hardcover For the first time, the print edition comes in hardcover (for the same price). Being able to offer this makes me very happy. The hardcover book looks much better and is more likely to stay open when laid flat on a table. We also increased the page size from 15x23 cm (6x9 in) to 18x25 cm (7x10 in) to keep the page count manageable (Amazon's print on demand service limits hardcover books to 550 pages). I hope you enjoy the new edition. If you decide to buy the book or if you bought it in the past, thank you very much! And if you're willing to write a review on Amazon, we'd appreciate it.