Fatbobman's Swift Weekly #144
When Every Data Write Comes at a New PriceRecently, OpenAI’s Codex was found to have a logging issue: the program kept writing large volumes of logs to a local database, causing the files to grow continuously and generating far more disk writes than normal. Bugs like this are hardly new. A few years ago, most people would probably have deleted the files, restarted the app, and waited for the next release to fix it. This time, however, the reaction was noticeably different. Instead of asking how much disk space remained, more people began wondering how much data had already been written to their SSDs, whether it might affect flash endurance, and how much more they would have to pay for the same amount of memory and storage when replacing their devices in the future. The Codex bug may not be any more serious than other runaway logging incidents in the past. What has changed is that every pointless write suddenly seems to come at a price again. As demand for AI compute continues to surge, memory manufacturers are increasingly prioritizing higher-margin, higher-demand products such as HBM, server memory, and enterprise SSDs. Consumer memory and SSDs are therefore receiving a smaller share of production capacity, while their prices continue to rise. Memory and flash have always been cyclical industries, so price increases and declines are nothing unusual. What makes the current situation unsettling is that it no longer appears to be merely another inventory cycle. It is accompanied by a longer-term shift of industry resources toward AI infrastructure. Even if prices eventually fall, consumers may not quickly return to the old assumption that large amounts of storage are practically free. As storage stops feeling inexhaustible, developers may also need to reconsider their attitude toward resources. When I first encountered computers, a common Apple II configuration had only 48 KB of memory. To make use of the additional 16 KB provided by an expansion card, developers had to arrange addresses, code, and data with great care, finding ways to make every byte count. A game spanning tens of gigabytes today inevitably offers graphics, sound, world scale, and interactive complexity that would have been unimaginable in the Famicom/NES era. Yet its enormous size does not guarantee that it will be more enjoyable than a game measured in only tens of kilobytes. This is not to say that modern software should not grow larger. What is worth examining is how, over many years, developers have grown accustomed to storage capacities increasing naturally and networks becoming ever faster. As long as there is still room for logs, caches, and temporary data, few people stop to ask why they exist or when they will be deleted. Expensive SSDs will not automatically produce better software, nor will memory shortages suddenly make developers smarter. But once hardware can no longer be assumed to grow without limit, engineering questions that have long been overlooked begin to resurface. I do not miss the days when developers had to struggle within a few dozen kilobytes. What is worth recovering is not the scarcity itself, but an engineering habit that once felt natural and has gradually faded away: knowing why every byte arrives—and when it will leave. Previous Issue|Newsletter Archive 📢 Sponsor Fatbobman’s Swift WeeklyPromote your product to Swift & iOS developers across: - Blog: 50,000+ monthly visitors Perfect for developer tools, courses, and services. Enjoyed this issue? Buy me a coffee ☕️ Recent RecommendationsSwift Task lifetime when an iOS device is lockedThis Q&A comes from the Apple Developer Forums. The original poster found that a Swift Task making several sequential REST requests would sometimes complete normally after the device was locked, sometimes pause, and occasionally time out. DTS engineer Quinn “The Eskimo!” explains that Swift Concurrency runs entirely within the app process. Once iOS suspends that process, the worker threads executing the Task also stop, and the Task itself receives no additional background execution privileges. This behavior can be especially confusing when networking is involved. If the app is suspended while a URLSession request is in progress, the request may fail because the connection becomes defunct. When the process resumes, developers may see a timeout or networking error rather than the Task continuing from where it paused and completing successfully. Quinn outlines four possible approaches: delay process suspension, stop in-flight requests before the app becomes eligible for suspension, allow requests to fail and implement retry and error recovery, or use a URLSession background session. anyAppleOS in Swift 6.4In the past, declaring availability for an API shared across Apple platforms required developers to list each platform and its corresponding OS version separately. Because version numbers differed across platforms for many years, these declarations were not only verbose but also prone to omissions and versioning mistakes. With Apple’s platforms adopting aligned major version numbers starting at 26, Swift 6.4 introduces Artem Mirzabekian introduces the new syntax and explains how it differs from platform-specific availability, The Anatomy of a Reusable SwiftUI ViewMore developers are trying to make the APIs of their reusable SwiftUI views feel as close as possible to Apple’s own designs, but there is often no clear methodology for putting that goal into practice. Alexander Weiß shares his approach: first determine whether a component is semantic, describing a functional concept, or prescriptive, carrying a clearly defined visual form. From there, define its semantics, valid states, data flow, and interaction behavior. Components should also follow SwiftUI’s state-management conventions, use immutable values, Binding, and State appropriately, and treat accessibility, environment values, and stable view identity as part of the design rather than focusing only on the shape of the call site. Using Card, Tag, and Rating as examples, the article demonstrates concrete implementations involving initializers, custom View Styles, and environment values. The central idea is not simply to imitate the appearance of Apple’s APIs, but to make custom components genuinely fit into the SwiftUI ecosystem through their composition model, state flow, interaction behavior, accessibility support, and environmental adaptation. The hidden cost of unstable SwiftUI environment defaultsThe Natalia Panferova uses I also analyzed this issue in SwiftUI Environment: Concepts and Practice. The root cause lies in how the Make Vertical Parallax for ScrollView in SwiftUIEarly 2D games created rich visual depth at very little cost by moving different image layers at different speeds. In SwiftUI, however, the difficult part of implementing scroll-based parallax is usually not calculating the offset, but continuously obtaining each view’s position within a The introduction of Toolsswift-span-algorithms: Adding Algorithmic Capabilities to SpanWhen working with contiguous memory, Swift developers traditionally had two main choices. Types such as Introduced in Swift 6.2, David Retegan created swift-span-algorithms to fill that gap. The library adds searching, comparison, trimming, chunking, sliding windows, splitting, cursor-based operations, and other utilities for Span, RawSpan, MutableSpan, and InlineArray. It is designed around zero hidden allocations and constant additional space, extending Span’s algorithmic capabilities while continuing to respect its lifetime constraints. Thanks for reading Fatbobman’s Swift Weekly! This post is public so feel free to share it. 当每一次写入都有了新价格最近,OpenAI 的 Codex 被发现存在一个日志写入问题:程序会持续向本地数据库写入大量日志,导致文件不断膨胀,并产生远超正常水平的磁盘写入。类似的 Bug 过去并不少见。放在几年前,人们大概只是删除文件、重启应用,然后等待下一个版本修复。 但这一次,大家的反应明显不同。比起“还剩多少磁盘空间”,更多人开始关心 SSD 已经累计写入了多少数据,会不会影响闪存寿命,以及未来更换设备时,需要为同样容量的内存和存储多付多少钱。 Codex 的 Bug 未必比过去那些失控的日志程序更加严重。真正发生变化的是:每一次无意义的写入,似乎都重新有了价格。 随着 AI 算力需求迅速增长,存储器厂商越来越倾向于优先保障 HBM、服务器内存和企业级 SSD 等利润更高、需求更旺盛的产品。消费级内存和 SSD 能够分配到的产能因此受到挤压,价格也不断走高。 内存和闪存本来就是典型的周期性行业,价格上涨和下跌并不罕见。但这一轮变化令人不安的地方,在于它似乎不再只是一次简单的库存周期,而是伴随着产业资源向 AI 基础设施长期倾斜。 即使价格最终仍会回落,消费者恐怕也很难迅速回到过去那种“大容量近乎免费”的心理预期。 当存储不再显得取之不尽时,开发者或许也应该转变对资源时的态度。 在我最开始接触电脑时,Apple II 常见的内存配置只有 48 KB。为了使用扩展卡额外提供的 16 KB 空间,开发者需要仔细安排地址、代码和数据,想方设法把每一个字节都利用起来。 今天一个数十 GB 的游戏,必然拥有 FC 时代无法想象的画面、声音、世界规模和交互复杂度。然而,巨大的容量并不能保证它带来的乐趣一定超过一个只有几十 KB 的游戏。 这并不是说现代软件不应该变大。真正值得思考的是,在过去很多年中,开发者已经习惯了存储容量会自然增长、网络会不断变快。日志、缓存和临时数据只要暂时还放得下,就很少有人追问它们为什么存在,又将在什么时候被删除。 昂贵的 SSD 不会自动创造优秀的软件,内存短缺也不会让开发者突然变得更加聪明。但当硬件不再被默认会无限增长时,那些曾经被忽视的工程问题便会重新浮出水面。 我并不怀念那个需要在几十 KB 中反复腾挪的时代。 真正值得重新拾起的,并不是资源匮乏,而是那种曾经十分自然、后来却逐渐消失的工程习惯: 知道每一个字节为什么到来,也知道它将在什么时候离开。 如果您发现这份周报或我的博客对您有所帮助,可以考虑通过 Buy Me a Coffee 支持我的创作。 近期推荐iOS 设备锁定后,Swift Task 能运行多久?(Swift Task lifetime when an iOS device is locked)这是一篇来自 Apple Developer Forums 的问答。提问者发现,一个会串行执行多个 REST 请求的 Swift Task,在设备锁定后有时能够正常完成,有时会暂停,甚至出现超时。DTS 工程师 Quinn “The Eskimo!” 解释道,Swift Concurrency 完全运行在应用进程中;一旦 iOS 挂起进程,执行 Task 的工作线程也会停止,Task 本身并不会获得额外的后台运行能力。 这种机制在网络请求中尤其容易造成困惑。应用被挂起时,正在进行的 URLSession 请求可能因连接失效而失败;进程恢复后,开发者看到的可能是请求超时或网络错误,而不是 Task 从暂停处继续并顺利完成。Quinn 给出了四种处理方向:设法延缓进程挂起、在应用即将被挂起时停止请求、允许请求失败并做好重试与错误恢复,或者使用 URLSession 的后台会话。 Swift 6.4 中的 anyAppleOS (anyAppleOS in Swift 6.4)过去,为跨 Apple 平台共享的 API 声明可用性时,开发者需要分别列出各个平台及其对应的系统版本。由于不同平台的版本号长期不一致,这类声明不仅冗长,也容易出现遗漏或版本填写错误。随着 Apple 各平台从 26 开始统一版本号,Swift 6.4 引入了 Artem Mirzabekian 介绍了这一新语法,并梳理了它与平台专属可用性、 可复用 SwiftUI 视图的设计剖析 (The Anatomy of a Reusable SwiftUI View)越来越多的开发者在构建可复用 SwiftUI 视图时,都希望其 API 尽可能贴近 Apple 官方的设计方式,但具体如何落地,往往缺少一套清晰的方法。Alexander Weiß 给出了自己的设计思路:首先判断组件属于描述功能概念的语义型组件,还是具有明确视觉形态的规定型组件,再梳理其语义、合法状态、数据流与交互行为。同时,组件还应遵循 SwiftUI 的状态管理方式,正确使用不可变值、Binding 与 State,并将无障碍支持、环境值和视图身份稳定性纳入设计,而不只是关注 API 的调用形式。 文章通过 Card、Tag 和 Rating 三个示例展示了初始化方法、自定义 View Style 和环境值等具体实现。这套方法的核心并非简单模仿 Apple API 的外形,而是让自定义组件在组合方式、状态流转、交互行为、无障碍支持和环境适配等方面真正融入 SwiftUI 体系。 SwiftUI 环境默认值不稳定的隐性成本 (The hidden cost of unstable SwiftUI environment defaults)
Natalia Panferova 使用
使用 visualEffect 为 SwiftUI ScrollView 创建纵向视差效果 (Make Vertical Parallax for ScrollView in SwiftUI)早期的二维游戏通过让不同图层以不同速度移动,用很低的成本便营造出了富有层次感的视觉效果。但在 SwiftUI 中实现滚动视差,真正麻烦的通常不是计算偏移量,而是持续获取每个视图在
工具swift-span-algorithms: 给 Span 补上算法能力在处理连续内存时,Swift 过去主要有两类选择:使用 Swift 6.2 新增的 David Retegan 开发的 swift-span-algorithms 正是对这一缺口的补充。它为 Span、RawSpan、MutableSpan 和 InlineArray 提供查找、比较、修剪、分块、滑动窗口、切分及游标(Cursor)等操作。整个库零以无隐藏分配和常数级额外空间为设计目标,在扩展算法能力的同时,仍然遵守 Span 的生命周期约束。 Welcome to my blog Fatbobman's Swift Blog( 肘子的Swift记事本 )
|
