Fatbobman's Swift Weekly #143
When Linux Becomes "Air": Containers, Agents, and a "Desktop War" That No Longer Matters
When Linux Becomes “Air”: Containers, Agents, and a “Desktop War” That No Longer Matters
A week ago, Microsoft released the public preview of native Windows 11 container support that requires no Docker. Combined with Apple’s recent 1.0 release of its container manager (Apple Container), both major desktop operating systems have now deeply integrated Linux containers as first-class citizens of the system.
This has sparked an interesting debate. Some see it as Linux’s ultimate victory: it never truly won the desktop market, yet it is now everywhere. Others ask the opposite question: when both Windows and macOS can run Linux containers smoothly and with little overhead, is this really a victory for Linux — or the beginning of its complete “commoditization” and “invisibility”?
These two views may seem contradictory, but they both point to the same fact: the role of Linux is changing.
In the past, when we talked about an operating system, we were usually talking about a complete platform — one with its own desktop, applications, development model, user habits, and ecosystem boundaries. Windows is a platform, macOS is a platform, and Linux distributions are, of course, platforms too. Around these platforms, people debated market share, user experience, compatibility, and that “Year of the Linux Desktop” joke that has been recycled for decades.
But containers have changed the structure of the question.
In modern software development, Linux increasingly appears not as “the operating system you are using,” but as “the default runtime environment.” Developers rarely say “I deployed to Linux.” They are far more likely to say “I deployed to Kubernetes,” “I’m running on the cloud,” or “I used a container image.”
This shift will become even more pronounced in the age of AI agents. As agents evolve from simple chat assistants into tools that actually execute tasks, what they need is no longer just a conversational interface, but a lightweight, instantly bootable, fully isolated, and easily disposable execution environment. Containers are a natural fit for this role. And as more and more tasks are carried out through agents, the interface where humans interact directly with the operating system is quietly losing weight — the outcome of the decades-long “desktop war” matters less and less.
Linux, then, is outgrowing its identity as a “platform.” It never won the desktop market share battle, yet it has made its way into the foundation of nearly every modern computing system. It never convinced everyone to switch to Linux, yet it has compelled every platform to support the way Linux runs.
The highest form of victory is not having everyone chant your name, but having everyone depend on you — while barely remembering you’re there. This is a victory where silence speaks louder than words.
Previous Issue|Newsletter Archive
📢 Sponsor Fatbobman’s Swift Weekly
Promote your product to Swift & iOS developers across:
- Blog: 50,000+ monthly visitors
- Newsletter: 4,000+ subscribers, 53% open rate
Perfect for developer tools, courses, and services.
Enjoyed this issue? Buy me a coffee ☕️
Original
Debugging Notes on Two SwiftUI Animation Bugs
Easy-to-use animation has always been one of SwiftUI’s defining features. But the nature of a declarative framework is a double-edged sword: once an animation misbehaves, tracking down the cause is often trickier than in an imperative framework. This post records two SwiftUI animation bugs I ran into over the past two weeks—less a set of solutions than an account of the hunt itself, shared in the hope that the thought process proves useful the next time you face something similar.
Recent Recommendations
Task Property: Reusing Stateful Business Logic for SwiftUI Views
When encapsulating stateful business logic in SwiftUI, what comes to mind first? Putting it in the view? Writing a modifier? Rick Van Voorden offers a less common but distinctly SwiftUI-flavored perspective: using DynamicProperty to extract stateful business logic out of the view, encapsulating it as reusable dynamic properties and letting views return to a purer declarative expression.
The TaskProperty in the project is merely a helper primitive for managing the lifecycle of asynchronous Tasks within custom dynamic properties. It is practical, but not what the README really wants to emphasize. Starting from the question of “how to reuse stateful business logic,” the author gradually demonstrates that DynamicProperty is not just the mechanism behind @State, @Binding, and @Environment—it can also serve as a way to organize and reuse stateful business logic.
Articles about custom
DynamicPropertyare rare, and what distinguishes this one is that it does not stop at API instruction. Instead, it brings the question back to the organization of business logic itself: is there shareable stateful logic mixed into your Views? Could that logic be extracted into custom dynamic properties that sit closer to the SwiftUI lifecycle?
Why My SwiftUI Map Bounced in Heading-Follow Mode?
Emre Degirmenci ran into a classic SwiftUI + MapKit boundary problem in a TCA-based map application: in heading-follow mode, the map kept jittering, the camera jumped, and the tracking state even exited unexpectedly. Interestingly, the same Map component worked fine in another app built with MVVM, which shifted the question from “an implementation mistake” to “whether the state synchronization model is sound.”
The root cause is that MapKit generates high-frequency camera updates in heading-follow mode, while the original implementation wrote those updates back to the TCA Store through two-way binding, creating a loop of “MapKit drives → state updates → state drives MapKit again” that broke the system’s own continuous animation logic. The fix was to leave camera changes under MapKit’s own control and intervene explicitly only when necessary, thereby avoiding conflicts between state and system-driven behavior.
SwiftUI 3D is Flat
In UIKit / AppKit, Core Animation’s CATransformLayer provides a genuinely shared 3D space with depth sorting, so many developers naturally assume that SwiftUI’s rotation3DEffect and projectionEffect are built on a similar 3D scene. But Mihaela Mihaljević Jakić shows through an experiment that SwiftUI has no unified 3D space or depth-buffering mechanism. After 3D transformations, multiple views remain “independent 2D projections,” which leads to typical occlusion errors—for example, a back face covering a front face.
This behavior is not a defect; it looks more like a deliberate design choice in SwiftUI: constraining 3D capabilities to the projection level of individual views rather than introducing a full 3D scene and hierarchy system.
Introducing the Safari MCP server for web developers
In today’s AI coding agent ecosystem, browser automation has long been dominated by the Chrome / Chromium stack as the de facto standard (Playwright, Puppeteer, CDP, etc.), with Safari mostly serving as a compatibility-verification environment.
The Safari MCP server (Safari Technology Preview 247) aims to change that: it exposes Safari’s browser session capabilities to agents, giving them direct access to the DOM, network requests, console logs, screenshots, and page state, so that debugging and analysis can happen in Safari’s real runtime environment. This moves Safari into the main path of the agent toolchain, rather than relying on indirect inference from Chromium or cross-browser switching for verification.
noUI()
As AI agent tools work their way deeper into development and content-production workflows, the role of UI is being reexamined. Starting from a DOS-style command interface, Jordan Morgan poses a question worth pondering: when more and more operations can be performed directly by agents through natural language, does UI still need to exist in the form of an “explicit interface”?
The part of the article that fascinated me most is the interactive terminal interface the author built with JavaScript and CSS. This design is not merely an example or a demo—it embeds the article’s argument itself into an operable UI, drawing readers into the discussion of UI’s changing form precisely through the act of “using an interface.” Here, UI is not just a vehicle of expression; it becomes part of the argument.
What does Activity Monitor measure?
Since AI agents entered everyday development workflows, many developers have had a similar experience: the Mac’s fans spin up more often and memory pressure rises noticeably, yet the CPU / Energy figures shown in Activity Monitor often fail to match that intuition.
Through controlled experiments with powermetrics and a variety of real workloads, Howard Oakley shows that the CPU % in Activity Monitor is closer to a simple sum of each CPU core’s active residency than to a “utilization percentage” in the traditional sense; GPU % is likewise only an approximation of active residency; and Energy Impact mainly reflects a CPU-level power estimate—it neither includes the GPU nor captures how energy consumption changes over time particularly well.
Tools
Quiver: Learning Linear Algebra and Classical Machine Learning with Swift
Wayne Bishop has long maintained Swift Algorithms & Data Structures, an e-book on algorithms and data structures for Swift developers. In its latest fifth edition, the book has extended beyond traditional algorithms and data structures into vectors, matrices, and similarity computation; Quiver pushes that path further into numerical computing, statistics, and classical machine learning.
Quiver is a pure Swift, zero-dependency library for linear algebra, statistics, and classical machine learning. It directly extends the Swift standard library’s Array, emphasizing value semantics, Codable, Sendable, and lightweight on-device execution on Apple platforms. Its goal is not to replace the Python numerical ecosystem, but to give Swift developers an entry point for understanding linear algebra, training small models, and bringing the results back into an App—all in a familiar language. In the later chapters of Swift Algorithms & Data Structures, Wayne uses Quiver as the companion tool for the math and machine-learning fundamentals.
SwipeCell v3: A Native SwiftUI Swipe Menu
At WWDC 2026, SwiftUI’s new swipeActionsContainer() finally let swipe menus step outside of List, serving ScrollView, lazy stacks, and more custom containers. Unfortunately, this capability currently requires system versions corresponding to anyAppleOS 27.
SwipeCell was the first third-party library I wrote six years ago, when I had just entered Swift development. The old versions were naive, but they also accompanied me through the changes in SwiftUI’s swipe interactions over the years. I recently gave it a complete rewrite and released v3: the new API is more SwiftUI-idiomatic, the configuration is more complete, the interaction feel has been re-polished, and macOS support has been added.
SwipeCell v3 is currently published on the v3-beta branch and remains in beta. You are welcome to try it out and report any issues you encounter.
Thanks for reading Fatbobman’s Swift Weekly! This post is public so feel free to share it.
当 Linux 成为“空气”:容器、Agent 与不再重要的“桌面之争”
一周前,微软推出了无需 Docker 的 Windows 11 原生容器支持的公开预览;再结合苹果不久前发布的容器管理器(container)1.0 正式版,一时间,两大主流桌面操作系统都将 Linux 容器深度集成为了系统的一等公民。
这件事引发了一场有趣的讨论。有人认为,这是 Linux 的最终胜利:虽然它始终没能真正赢下桌面市场,但它已经无处不在;也有人提出反问:当 Windows 和 macOS 都能相对顺畅、轻量地运行 Linux 容器时,这究竟是 Linux 的胜利,还是它被彻底“工具化”和“隐形化”的开始?
这两种说法看似相反,其实都触碰到了同一个事实:Linux 的角色正在发生变化。
过去,我们谈论操作系统时,通常是在谈论一个完整的平台。它有自己的桌面、应用、开发模型、用户习惯和生态边界。Windows 是一个平台,macOS 是一个平台,Linux 发行版当然也是一个平台。围绕这些平台,人们讨论份额、体验、兼容性,以及那个已经被反复调侃了几十年的“Linux 桌面元年”。
但容器改变了这个问题的结构。
在现代软件开发中,Linux 越来越少以“你正在使用的操作系统”的形式出现,而是以“默认运行环境”的形式存在。开发者不一定会说“我部署到了 Linux”,他们更可能说“我部署到了 Kubernetes”、“我跑在云上”、“我用了一个容器镜像”。
这种变化在 AI Agent 时代会更加明显。随着 Agent 从简单的聊天助手转向能够真正执行任务的工具,它们需要的不再只是一个对话界面,而是一个轻量、秒级启动、完全隔离且易于销毁的执行环境。容器天然适合承担这种角色。而当越来越多的任务经由 Agent 完成,人与操作系统直接交互的界面,其权重也在悄然下降——那场持续了数十年的“桌面之争”,胜负已经愈发不重要了。
所以,Linux 正在超越“平台”这个身份。它没有成为桌面操作系统份额的赢家,却进入了几乎所有现代计算体系的底层。它没有让所有人都改用 Linux,却让所有平台都不得不支持 Linux 的运行方式。
不是让所有人都高喊你的名字,而是让所有人都离不开你,却又想不起你。这种胜利无声胜有声。
如果您发现这份周报或我的博客对您有所帮助,可以考虑通过 Buy Me a Coffee 支持我的创作。
原创
两个 SwiftUI 动画 Bug 排查小记
易用的动画一直是 SwiftUI 的主要特色之一。但声明式框架的特性是一把双刃剑:动画一旦出现异常,排查往往比命令式框架更棘手。本文记录了过去两周里,我在开发中遇到的两个与 SwiftUI 动画有关的 Bug。与其说是解决方案,不如说是一段排查的心路——希望能为你面对类似问题时开阔一点思路。
近期推荐
利用属性机制重构状态化业务逻辑 (Task Property: Reusing Stateful Business Logic for SwiftUI Views)
在 SwiftUI 中封装带状态的业务逻辑,你第一时间会想到什么方式?放进视图?写成 modifier?Rick Van Voorden 提供了一个不太常见但很有 SwiftUI 味道的视角:利用 DynamicProperty 将状态化业务逻辑从 View 中抽离出来,封装为可复用的动态属性,让 View 回归更纯粹的声明式表达。
项目中的 TaskProperty 只是一个辅助原语,用于在自定义动态属性中管理异步 Task 的生命周期。它很实用,但并不是这篇 README 真正想强调的重点。作者从“如何复用 Stateful Business Logic”这个问题出发,逐步展示了 DynamicProperty 不只是 @State、@Binding、@Environment 背后的机制,也可以成为组织和复用状态化业务逻辑的一种方式。
关于自定义
DynamicProperty的文章并不多,而本文的特点在于,它没有停留在 API 使用教学上,而是把问题放回业务逻辑组织本身:你的 View 中是否混入了可共享的状态逻辑?这些逻辑是否可以被抽取为更贴近 SwiftUI 生命周期的自定义动态属性?
SwiftUI 地图在航向跟随模式下为何会抖动?(Why My SwiftUI Map Bounced in Heading-Follow Mode?)
Emre Degirmenci 在一个基于 TCA 的地图应用中遇到了一个典型的 SwiftUI + MapKit 边界问题:在 heading-follow 模式下,地图出现持续抖动、相机跳动,甚至定位状态异常退出。有意思的是,同样的 Map 组件在另一个 MVVM 架构的应用中却没有问题,这使得问题从“实现错误”转向了“状态同步模型是否合理”。
核心原因在于 MapKit 在 heading-follow 模式下会产生高频相机更新,而原实现通过双向绑定将更新数据回写到 TCA Store,造成了“MapKit 驱动 → 状态更新 → 再驱动 MapKit”的回路,破坏了系统自身的连续动画逻辑。修复方式为让相机变化保持由 MapKit 自身控制,只在需要时进行显式干预,从而避免状态与系统驱动之间的冲突。
SwiftUI 3D is Flat
在 UIKit / AppKit 中,Core Animation 的 CATransformLayer 提供了真正的共享 3D 空间与深度排序能力,因此不少开发者会自然地认为 SwiftUI 的 rotation3DEffect、projectionEffect 也建立在类似的 3D 场景之上。但 Mihaela Mihaljević Jakić 通过一个实验指出:SwiftUI 并不存在统一的 3D 空间或深度缓冲机制。多个视图在 3D 变换后的结果仍然是“各自独立的 2D 投影”,因此会出现典型的遮挡错误,例如“背面覆盖正面”。
这种行为并非缺陷,而更像是 SwiftUI 有意的设计选择:将 3D 能力限制在单个 view 的投影层面,而不是引入完整的 3D 场景与层级体系。
Safari 推出面向 Web 开发者的 MCP (Introducing the Safari MCP server for web developers)
在当前 AI coding agent 生态中,浏览器自动化长期以 Chrome / Chromium 体系为事实标准(Playwright、Puppeteer、CDP 等),Safari 通常更多作为兼容性验证环境。
Safari MCP server(Safari Technology Preview 247)试图改变这一点:它将 Safari 浏览器会话能力暴露给 agent,使其可以直接访问 DOM、网络请求、控制台日志、截图以及页面状态,从而在 Safari 的真实运行环境中完成调试与分析。这使 Safari 开始进入 agent toolchain 的主路径,而不再只是依赖 Chromium 的间接推断或跨浏览器切换验证。
AI 时代下的“无 UI”趋势思考 noUI()
在当前 AI agent 工具逐渐深入开发与内容生产流程的背景下,UI 的角色正在被重新审视。Jordan Morgan 从 DOS 风格的命令界面切入,提出一个值得思考的问题:当越来越多的操作可以直接由 agent 通过自然语言完成时,UI 是否仍然需要以“显式界面”的形式存在?
文章中最吸引我的部分,是作者基于 JavaScript 与 CSS 构建了一个可交互的终端界面。这个设计并不仅仅用于示例或演示,而是将文章的论述本身嵌入到一个可操作的 UI 中,使读者在“使用界面”的过程中进入对 UI 形态变化的讨论之中。UI 在这里不只是表达载体,也成为论证的一部分。
重新认识 Mac 活动监视器的各项性能指标 (What does Activity Monitor measure?)
在 AI agent 逐渐进入日常开发流程之后,很多开发者都会有类似的体验:Mac 风扇更频繁启动、内存压力明显上升,但 Activity Monitor 中显示的 CPU / Energy 数值却往往与直观感受并不一致。
Howard Oakley 通过 powermetrics 与多种真实负载对照实验指出,Activity Monitor 中的 CPU % 更接近各 CPU core active residency 的简单叠加,而非传统意义上的“利用率百分比”;GPU % 同样只是 active residency 的近似表达;而 Energy Impact 则主要反映 CPU 层面的功耗估算,既不包含 GPU,也没有很好地刻画时间维度上的能耗变化。
工具
Quiver:用 Swift 学线性代数与经典机器学习
Wayne Bishop 长期维护的《Swift Algorithms & Data Structures》是一部面向 Swift 开发者的算法与数据结构电子书。在最新的第五版中,这本书已经从传统算法、数据结构延伸到向量、矩阵和相似度计算;而 Quiver 则把这条路径继续推进到数值计算、统计和经典机器学习。
Quiver 是一个纯 Swift、零依赖的线性代数、统计与经典机器学习库。它直接扩展 Swift 标准库的 Array,强调值语义、Codable、Sendable,以及在 Apple 平台上的轻量端侧运行。它的目标不是替代 Python 数值生态,而是为 Swift 开发者提供一个用熟悉语言理解线性代数、训练小型模型,并将结果带回 App 的入口。Wayne 在《Swift Algorithms & Data Structures》后续章节中,也正是以 Quiver 作为数学与机器学习基础内容的配套工具。
SwipeCell v3:SwiftUI 原生的侧滑菜单
WWDC 2026 上,SwiftUI 通过新的 swipeActionsContainer() 终于让侧滑菜单走出了 List,可以服务于 ScrollView、懒加载栈以及更多自定义容器。但遗憾的是,这项能力目前需要 anyAppleOS 27 对应的系统版本才能使用。
SwipeCell 是我六年前刚进入 Swift 开发时写下的第一个第三方库。旧版本很稚嫩,但也陪我见证了 SwiftUI 侧滑交互这些年的变化。最近我对它做了彻底的重写,推出了 v3 版本:新的 API 更 SwiftUI 化,配置更完整,交互手感也重新打磨,并加入了 macOS 支持。
目前 SwipeCell v3 发布在 v3-beta 分支,仍处于 beta 阶段,欢迎试用,也欢迎反馈使用中的问题。
求贤
资深 iOS / Swift 工程师
Speak:YC 孵化、OpenAI 多轮投资的 AI 语言学习独角兽。
工作地:上海。
一家在海外多个市场长期验证、商业化成熟的 AI-native 语言学习公司,正在从 0 -> 1 组建中国核心工程团队。团队小而美、不内卷,重度使用 AI(Cursor / Claude Code 等),看重工程 owner 意识和 agentic engineering 工作方式。
作为中国团队的早期核心 iOS,你将全程参与技术选型,搭建国内 iOS 完整基建、对接本土支付 / 登录 / 合规 SDK、优化 AI 语音实时交互体验,并与全球团队英文协作。
期待你具备:
5 年以上 iOS 原生(Swift)开发经验,有上线的消费级产品
扎实的原生 iOS 深度(性能、稳定性、架构、弱网优化等)
AI-native 工作流(日常用 Cursor / Claude / Copilot 等)
书面英文胜任 PR / Slack / 文档,口语 B1+、能清晰表达技术想法
有国内 App Store 上架 / 本土 SDK 经验者优先;音视频 / RTC / 语音方向加分
👉 详细参见
有意向者欢迎投递英文简历至 a.suen@usespeak.com


