Issue #138

Stability > New Features

Cover for Weekly Issue 138

Photo by Scott Kelley on Unsplash

Whether it is SwiftUI or SwiftData, these foundational frameworks, into which Apple poured so much hope, promised a bright future when they were first introduced. However, their actual trajectory seems to have diverged from the original blueprint. The deeper I dive into these frameworks, the more I marvel at their elegant architectural design—yet I also find myself speechless at their underwhelming implementation. Watching the halo around these designs gradually fade, I cannot help but feel a sense of wistfulness.

Rumor has it that in the upcoming operating systems to be released this year (including iOS 27 and macOS 27), Apple will adopt a refinement strategy similar to the Mac OS X Snow Leopard era. This means prioritizing system stability, performance optimization, clearing legacy code, and squashing bugs over introducing disruptive visual redesigns or a flurry of new low-level features. If this indeed turns out to be the case, it would be deeply reassuring. Looking back at Issue #006 of the weekly newsletter published more than two years ago, rumors also circulated back then that Apple would focus on fixing existing defects and improving performance. Yet, judging by the actual user experience over the past two years, that goal seems to have fallen short.

With WWDC 26 less than ten days away, rather than more flashy new features, what I look forward to most this year is Apple delivering a grounded, more stable experience for both developers and consumers.

Original

Taming Row Height and Spacing Jumps in SwiftUI List with a Custom Layout

In SwiftUI, adding animation to view state changes often takes very little code, but List does not always produce the kind of smooth transition we expect. This is especially noticeable when the height of content inside a row changes dynamically—for example, when a subtitle goes from empty to non-empty, or when updated text changes its line count. In these cases, the system’s default layout process can easily cause the row height to jump abruptly, leading to visible flickering, clipping, or sudden spacing changes. Starting from this common issue, this article gradually breaks down why dynamic row-height animations fail in List, and builds a solution entirely based on native SwiftUI capabilities through custom Layout, Animatable, LayoutValueKey, and state decoupling.

This is not an article primarily aimed at providing a ready-to-use component. Rather than focusing only on the final code, I hope to use this problem to outline a way of investigating SwiftUI layout issues: first understand why the framework “does not behave as expected,” then reorganize state, measurement, and layout along the grain of its mechanisms, so that the animation happens at the correct level.

Recent Recommendations

Stateless Actors

Actors are usually understood as tools for protecting mutable state, so an actor with no stored properties—a seemingly stateless actor—naturally raises the question: does it have any reason to exist? This article explores that question through examples such as NetworkClient, custom global actors, custom executors, and file-system access. It shows that stateless actors are not necessarily unreasonable, but they may introduce extra costs such as serialization, protocol-adaptation difficulties, and type-system propagation. The key question is what problem they are actually solving.

The most important point in the article is the “first rule of actors” proposed by Matt Massicotte: just like with any synchronization primitive, before using an actor, you should be able to clearly explain why it is necessary. A stateless actor is not necessarily wrong, but it may indicate that we are using an actor to solve a problem that does not actually require one. Only when it clearly takes on responsibilities such as isolation, serialization, executor adaptation, or protection of external state does it become a reasonable design.


Building a Custom Data Store in SwiftData

Many developers tend to think of SwiftData as Apple’s high-level wrapper around SQLite, but that underestimates its potential as a framework for object-graph management and persistence coordination. Whether we are talking about SwiftData or Core Data, their more important capability is not merely reading and writing a database for us, but keeping model objects, queries, context management, and the underlying storage clearly separated. As long as the underlying storage can exchange data in the way the framework expects, the data source does not have to be SQLite.

Mohammad Azam demonstrates this by implementing a JSON-file-based custom data store. The article shows that what SwiftData exchanges with the underlying store is not the live object marked with @Model, but a converted snapshot. Once you understand this, the responsibility boundaries of DataStoreConfiguration, DataStore, DefaultSnapshot, PersistentIdentifier, and fetch / save become much clearer: SwiftData is responsible for model objects, observation, change tracking, and SwiftUI integration, while the custom store is only responsible for reading and writing snapshots.

In Weekly Issue #127, I recommended DataStoreKit, a more engineering-oriented custom DataStore project. It does not simply replace SwiftData’s backend with JSON or file storage; instead, it attempts to reimplement a SwiftData-aware SQLite storage layer based on custom DataStore, with extensive work around predicate translation, inheritance, caching, persistent history, and background prefetching. Developers who want to explore this direction further can use it as an advanced reference.


Task Names in Swift Concurrency

GCD has queue labels, but tasks in Swift Concurrency long lacked a similar diagnostic identifier. With SE-0469 implemented in Swift 6.2, APIs such as Task, Task.detached, and task group addTask now support a name parameter. Developers can assign short, readable names to concurrent tasks, making it easier to locate specific execution units in LLDB, Instruments, and logs.

Artem Novichkov walks through the usage and limitations of task names, and reminds developers that a task name should be treated as diagnostic information, not as part of program logic. It is useful for debugging, performance analysis, and log investigation, but it should not carry business state.


UniqueBox, Ref, and MutableRef in Swift 6.4

Swift 6.4 continues the language’s evolution around ownership, borrow, noncopyable types, lifetime dependency, Span, and MutableSpan. Through the three types UniqueBox, Ref, and MutableRef, Artem Mirzabekian introduces Swift’s new expressive capabilities around storage location, ownership, and access lifetime. Their significance is not that ordinary business code should immediately start using these low-level building blocks, but that Swift is gradually elevating relationships that previously depended on class boxes, UnsafePointer, or compiler-internal reasoning into language models that can be written into API shapes and checked by the type system.

Specifically, UniqueBox expresses that “a value lives on the heap and is owned by a single owner,” while Ref and MutableRef correspond to shared reading and exclusive mutation within a given lifetime. In other words, these types do not merely add a convenient API for a specific business scenario; they provide a more precise low-level vocabulary for describing “where a value lives, who owns it, and who can access it.”


Clarification on Current CloudKit CKAsset File Size Limits

There has long been a confusing claim in the community around the file-size limit of CKAsset: some documentation has mentioned a 50 MB limit, but that mostly applies to CloudKit Web Services rather than CKAsset uploads through the native CloudKit framework on Apple platforms. This time, an Apple Frameworks Engineer gave a very clear answer on the developer forums: a single CKAsset supports up to 50 GB, assuming the user has enough remaining iCloud storage. Apps therefore need to correctly handle CKError.quotaExceeded.

I am introducing this Q&A in the weekly not just because it clarifies a number, but because it draws an important boundary: the fact that CKAsset supports large files does not mean large-file syncing is a simple or automatically reliable engineering problem. The follow-up discussion also mentions that large file transfers often need to consider background execution when an app is suspended or terminated, and can use long-lived CloudKit operations or schedule uploads through BGProcessingTask in BackgroundTasks. In other words, 50 GB answers the question “does CloudKit allow it?”; background transfer, failure recovery, quota handling, and user experience still need to be designed carefully by the app.


Providing Useful Debugging Information for Agents

As AI agents become increasingly involved in compiling, testing, and diagnosing Swift projects, a very practical problem has become more prominent: the output of xcodebuild is simply too long. If the complete log is handed directly to an agent, it not only consumes a large number of tokens, but also risks burying the useful information in noise. The Xcsift tool introduced by Lee young-jun in this article is designed precisely for this scenario. Unlike xcpretty, which is mainly aimed at human readability, Xcsift organizes xcodebuild / SwiftPM output into structured results that are more suitable for LLM consumption, including compile errors, warnings, test failures, coverage, and build timing.

One easily overlooked detail in AI-assisted development workflows is that we should not let agents “read everything and decide what matters by themselves.” Instead, we should try to perform filtering and structuring at the tool layer first. Xcsift is a practical solution built on top of existing xcodebuild output, while the Tuist team previously discussed structured build data beyond build logs in Teaching AI to Read Xcode Builds. Viewed together, they show two levels of build diagnosis in agentic coding: first reduce noise, then improve semantics.


The MiniSwift Story

I previously recommended MiniSwift in the weekly. At that time, the most fascinating part was that Ugur Toprakdeviren had implemented a Swift compiler frontend and WASM backend from scratch in C, without relying on LLVM, Clang, or Apple’s official toolchain. In this article, the author fills in the story behind the project: it did not begin as a “show-off compiler project,” but from a very specific question—could one get a more stable SwiftUI preview on canvas, free from the instability of WebView or Xcode Preview?

The reason MiniSwift is worth recommending again is that it has clearly taken a big step from an early compiler prototype toward its original goal. It no longer merely compiles Swift code to WASM; through a custom UIIR, canvas renderer, and diff engine, it can now render SwiftUI code directly into an interactive preview in the browser. Judging from the official demo, @State, basic layout, buttons, text, and some modifiers can already provide immediate feedback in the browser similar to SwiftUI Preview. In other words, the previously mentioned idea of a “SwiftUI browser preview that does not crash” is turning from a concept into a tool that can be experienced directly.

Tools

MistKit: Letting Server-Side Swift Access CloudKit

Developed by Leo G Dion, MistKit has a clear goal: to wrap Apple’s CloudKit Web Services REST API in a modern Swift interface, allowing server-side Swift, command-line tools, and environments such as Linux and Windows—where the native CloudKit framework is unavailable—to access the same CloudKit containers. It is not meant to replace the CloudKit framework on Apple platforms, but to fill the gap in scenarios where the native framework cannot be used directly.

The project builds its lower-level client on top of swift-openapi-generator, while providing higher-level capabilities such as async/await, type-safe CloudKit operations, structured errors, record querying and CRUD, record / zone changes, asset upload, and user-identity-related functionality. For authentication, it supports API Token, Web Auth Token, and Server-to-Server. Server-to-Server is mainly for the public database, while operations involving user context in private or shared databases require Web Auth Token. This makes it suitable for background tasks, CLIs, content catalogs, public database management, and data bridging between the web and Apple devices.

CloudKit is often seen as a “client-side service,” but MistKit makes it more natural for servers to participate in the CloudKit ecosystem. For example, a scheduled job could maintain a software version catalog, RSS aggregation content, or app asset packages in the public database; or, after user authorization, a backend could process data in a user’s private database. For apps already relying on CloudKit, it provides a path for extending data-processing capabilities beyond Apple platforms.

Related Weekly

Subscribe to Fatbobman

Weekly Swift & SwiftUI highlights. Join developers.

Subscribe Now