普通视图
AppStore卡审44小时的产品,重新提交后已经过审了。
SwiftUI 支持呼吸动画的图片切换小控件
Swift 扩展(Extension)指南——给现有类型“加外挂”的正规方式
【Swift 错误处理全解析】——从 throw 到 typed throws,一篇就够
【Swift 并发编程入门】——从 async/await 到 Actor,一文看懂结构化并发
《Flutter全栈开发实战指南:从零到高级》- 11 -状态管理Provider
欧陆风云 5 的经济系统
很早从“舅舅”那里拿到了《欧陆风云 5》的试玩版。因为开发期的缘故,更新版本后需要重玩,所以一开始只是陆陆续续玩了十几个小时。前段时间从阳朔攀岩回来,据说已经是发售前最后一版了,便投入精力好好玩了 50 小时,感觉非常好。
我没有玩过这个系列的前作,但有 800 小时《群星》的经验,还有维多利亚 2/3 以及十字军之王 2/3 的近百小时游戏时间,对 P 社的大战略游戏的套路还是比较了解的。这一作中有很多似曾相识的机制,但玩进去又颇为新鲜,未曾在其它游戏中体验过。
我特别喜欢 P 社这种在微观上使用简洁公式,宏观展现出深度的游戏设计。我试着对游戏的一小部分设计作一些分析,记录一下它的经济系统是如何构建的。
这里有一篇官方的开发日志:贸易与经济 其实说得很清楚。但没自己玩恐怕无法理解。
我在玩了几十小时后,也只模糊勾勒出经济系统的大轮廓。下面是我自己的理解,可能还存在不少错误。
EU5 的经济系统由人口/货币/商品构成,市场为其中介。
游戏世界由无数地区构成。地区在一起可以构成国家,也能构成市场。一个国家可以对应一个市场,也可以由多个市场构成,也可以和其它国家共享市场。
每个市场都会以一个地区为市场中心,这反应了这个地区的经济影响力,它不同于国家以首都为中心的政治版图。市场自身会产生影响力,而市场中心地区的所属国家则因其政治影响力而产生市场保护力,两相作用决定了市场向外辐射的范围。每个地区在每个时刻都会根据受周围不同市场的影响强弱,最终归属到一个唯一市场。
每个地区有单一的原产物资(商品)。原产在版图上不会改变,可以被人口开发,计入所属市场供给。
地区上可以修建生产建筑,生产建筑通过人口把若干种商品转换为一种商品。转换效率受地区的市场接入率影响。市场中心地区的接入率为 100% ,远离市场的地区接入率下降,在边远地区甚至为 0 (这降低了同样人口的工作效率)。注:原产不受市场接入率的影响。
市场每种商品有供给和需求。每种商品有一个额定价格。需求和供给的多寡决定了目标价格和额定价格的差距,目标价格在 10% 到 500% 间变化。实际价格每个月会向目标价格变动,变动速度受物价波动率影响。
商品的价格减去原料成本(原产物资没有原料成本)为其利润,利润以货币形式归属生产人口,并产生税基。
负利润的生产建筑会逐渐减员,削减产量,除非政府提供补贴。缺少原料的生产建筑会减产。
人口会对商品产生需求。食物类型的商品是最基本的需求。 不能满足食物需求的人口会饿死,不能满足其它需求的人口会产生不满。
对于单一市场:
- 人口在市场上产生商品需求。
- 生产建筑通过人口生产出商品供给市场。
- 市场上的供给和需求影响了商品价格。
- 人口通过生产获取货币形式的利润,并产生税基。
税基中的一部分货币留给人口,一部分以税收形式收归国库。
货币用来投资新增生产建筑,或对其升级。建筑升级需要商品,这部分商品以需求形式出现在市场。人口会用自己的钱自动投资建筑,玩家可以动用国库升级建筑。
多个市场间以贸易形式交换商品:
每个市场有一个贸易容量,贸易容量由市场中地区中的建筑获得。贸易容量用来向其它市场进出口商品。
市场所属国家拥有贸易竞争力,贸易竞争力决定了向市场交易的优先级。高优先级贸易竞争力的市场先消耗贸易容量达成交易。
商品在不同市场中的价差构成了贸易利润,其中需要扣除贸易成本(通常由两个市场中心间的距离决定)。贸易利润的一部分(由王权力度决定)进入国库,其它部分变为税基。
在国家主动进行贸易外,人口也有单独的贸易容量,自动在市场间贸易平衡供需。
我觉得颇为有趣的部分是这个经济系统中货币和商品的关系。
游戏中的生态其实是用商品构成的:人口提供了商品的基本需求,同时人口也用来生产它们。在生产过程中,转换关系又产生了对原料的需求。为了提高生产力,需要建造和升级建筑,这些建筑本身又是由商品转换而来。所以这么看来,是这些商品构成了这个世界,从这个角度完全不涉及货币。
但货币是什么呢?货币是商品扭转的中介。因为原产是固定在世界的各个角落的,必须通过市场和贸易通达各处。
建立一个超大的单一市场可以避免贸易,它们都直接计入市场中心。但远离市场中心生产出来的商品(非原产)受市场接入度的影响而削弱生产效率,所以这个世界只能本分割成若干市场。不同市场由于供需关系不同而造成了物价波动。价差形成贸易的利润,让商品流动。这很好的体现了货币的本质:商品流动的中介。
政府通过税收和其主导的国家贸易行为获得货币,同时也可以通过铸币获取额外收益(并制造通货膨胀)。再用这些货币去投资引导世界的发展:建造和升级生产建筑光有钱是不行的,必须市场上有足够的商品;没有钱也是不行的,得负担得起市场上对应商品的价格。
《Flutter全栈开发实战指南:从零到高级》- 10 -状态管理setState与InheritedWidget
Swift 泛型深度指南 ——从“交换两个值”到“通用容器”的代码复用之路
Swift 中的不透明类型与装箱协议类型:概念、区别与实践
惊险但幸运,两次!| 肘子的 Swift 周报 #0109
![]()
📮 想持续关注 Swift 技术前沿?
每周一期《肘子的 Swift 周报》,为你精选本周最值得关注的 Swift、SwiftUI 技术文章、开源项目和社区动态。
- 📬 在 weekly.fatbobman.com 免费订阅
- 💬 加入 Discord 与中文 Swift 开发者深入交流
- 📚 访问 fatbobman.com 查看数百篇深度原创教程
一起构建更好的 Swift 应用!🚀
惊险但幸运,两次!
我的岳父岳母的身体一向很好,尤其是岳父,八十多岁了从未住过院。但在短短的时间里,他们先后经历了两场惊魂时刻——好在结果都十分幸运。
先是岳母。那天我们刚从机场接她回家,发现她脸色不好,自述昨晚没睡好,似乎又有肾结石发作的迹象。正当我们决定取消外出用餐时,她突然开始剧烈发抖,但额头仍是凉的。测量血氧后发现指标在快速下降——即使立即开始吸氧,最低时也掉到了 78。
救护车到达时(约 40 分钟后),体温已升至 39.8℃;送医时更是接近 41℃。人的状态非常差。幸运的是,在此前她提到过肾结石的不适,医生据此快速展开检查,确诊为尿源性脓毒症——结石堵住输尿管,细菌在尿液中迅速繁殖,最终进入血液。 医生直言,若再晚些送来,后果可能不堪设想。想到她刚下飞机,我们也不禁后怕——幸亏航班没有延误,幸亏那天决定乘坐早班机。经过紧急手术引流后,她的状况在第二天便明显好转,数日后顺利出院。
不久之后,又轮到岳父经历一次“惊险但幸运”的考验。 在照顾岳母期间,他出现咳嗽并伴随低热。CT 显示只是支气管扩张,但考虑到年龄,我们坚持让他住院观察。 在例行心电图检查中,医生意外发现他有房颤,心率在 130–170 之间剧烈波动。令人吃惊的是,他本人毫无不适感。事后他说,今年 5 月体检时医生就提醒过有房颤,但他没当回事,也没有告诉我们。 由于心率过快,治疗重心立即转为控制心律。幸运再次眷顾——在使用胺碘酮(Amiodarone)数小时后,心率逐渐恢复至 80 以下,成功复律。如今虽然仍在住院,但情况稳定,只需出院后按医嘱服用控制心率与抗凝药物即可。这次的阴差阳错,也让他在不经意间避免了房颤可能带来的更严重后果。
短短一周内的两次意外,让人既感叹生命的脆弱,也更懂得珍惜当下。幸运往往属于那些及时行动、认真对待健康警示的人。愿我们都能对自己和家人的身体多一分关注,少一分侥幸。
近期推荐
让 onChange 同时监听多个值 onChange(anyOf:initial:_:)
onChange 是 SwiftUI 中常用的状态监听工具,开发者可以通过它在视图中针对某个值的变化执行逻辑。不过,尽管该修饰符历经多次改进,它仍然只能同时观察一个值。若要在多个状态变更时执行相同操作,就需要重复添加多个内容相同的 onChange 闭包。在本文中,Matt Comi 借助 variadic generics(可变参数泛型),让 onChange 能够同时监听多个值,从而构建出一个更高效、更优雅的解决方案。
SwiftUI 中的滚动吸附 (ScrollView snapping in SwiftUI)
从 iOS 17 开始,开发者可以通过 scrollTargetBehavior 控制 ScrollView 的滚动行为,比如按页面吸附或按视图吸附。Natalia Panferova 在这篇文章中详细探讨了该 API 的用法,并分享了实践经验和需要注意的陷阱:视图对齐模式要求每个吸附目标适配可见区域;当单个项目尺寸超过容器大小时,滚动会感觉"卡住";对于超大项目,需要考虑自定义 ScrollTargetBehavior。
在 精确掌控 SwiftUI 滚动:自定义 Paging 实现 一文中,我也介绍了如何通过自定义 ScrollTargetBehavior 解决横屏模式(Landscape)下滚动偏移、页面对齐不精确的问题。
Swift 类型检查器改进路线图 (Roadmap for improving the type checker)
作为 Swift 开发者,你一定不会对那句 "unable to type-check this expression in reasonable time" 感到陌生。为什么会出现这个编译错误?Swift 又将如何减少这种情况的发生?Swift 核心团队成员 Slava Pestov 在这份路线图中给出了详细的解释与改进方向。
该问题源自约束求解(constraint solving)的指数时间复杂度。为防止编译器陷入无休止的回溯,Swift 设定了两项限制:析取选择次数上限(100 万次) 和 求解器内存上限(512 MB)。Swift 6.2 通过优化底层算法实现了初步提速,而 Swift 6.3 引入的新析取选择算法与内存优化带来了显著改进:同一测试项目的类型检查时间从 42 秒降至 10 秒。Swift 团队的目标是在不牺牲语言表达力的前提下,通过算法与实现层的持续优化,将“指数最坏情况”压缩到更少、更边缘的实际场景中。
iOS Sheet 的现代化演进 (Playing with Sheet (on iOS))
在 iOS 上,Sheet 曾经意味着“全屏接管”——从底部滑出、阻挡一切、等待用户点击“完成”。但如今,这种模式已经过去。Apple 重新定义了内容的呈现方式:在新的设计哲学下,Sheet 不再是中断,而是节奏的一部分——它可以滑动、漂浮、扩展、折叠,让界面保持连贯与呼吸感。Danny Bolella 从多个层面展示了现代 Sheet 的可定制特性,并通过实例演示了这些特性如何让 Sheet 从“流程中断”转变为“上下文扩展”。
针对 Sheet 无法自动适应内容高度的问题,开发者可以通过
GeometryReader测量内容高度并结合.id()刷新的技巧来实现动态高度调整。
iOS 性能优化:Apple 工程师问答精选 (Optimize Your App's Speed and Efficiency: Q&A)
Anton Gubarenko 整理了 Apple “Optimize your app’s speed and efficiency” 活动中的 Q&A 内容,涵盖 SwiftUI 性能(闭包捕获优化、Observable 使用、@Binding vs let)、Liquid Glass 容器(GlassEffectContainer 的最佳实践)、Foundation Models 框架(多语言支持、并发使用、延迟优化)以及 Instruments 工具(Hitch vs Hang、新增 Power Profiler)等关键领域。
本次 Q&A 展现了 Apple 工程团队在性能调优层面的实践取向:通过细节分析与工具驱动,让优化从“黑盒经验”转变为“可度量、可验证的工程流程”。
Swift 中禁用单个弃用警告的技巧 (Workaround: how to silence individual deprecation warnings in Swift)
开发中难免必须使用一些被软废弃(deprecated)的 API。在开启“警告即错误”(-warnings-as-errors)后,将面临无法编译的窘境。不同于 Objective-C 可以使用 #pragma clang diagnostic 针对特定代码段禁用警告,Swift 至今没有等效机制。
Jesse Squires 分享了一个巧妙的解决方案:定义一个协议包装弃用 API,在扩展中实现时标记为 @available(*, deprecated),然后通过类型转换为协议类型来调用。编译器会通过协议见证表查找方法,从而“隐藏”弃用警告。虽然方案略显冗长,但对于必须使用遗留 API 的纯 Swift 项目很实用。
深入 Swift 底层:从二进制优化到逆向工程
以下几篇文章都偏硬核,适合关注工具链、运行时与二进制层面细节的读者。
-
static const in header cost: dyld ships with redundant 2KB data copy by Kyle Ye
通过 dyld 中
static const头文件定义被多处编译单元重复包含的案例,揭示了二进制体积膨胀的成因与代价,并提出修复方案。 -
Reverse engineer a swift binary by Erk Ekin
通过一个简单的登录程序,演示如何反汇编 Swift 可执行文件、定位字符串与条件分支,并通过修改指令和重新签名实现“补丁式”运行。
-
How do researchers reverse-engineer private frameworks? By Jacob Bartlett
介绍如何借助 MachOSwiftSection 从 Simulator runtime 抽取 Mach-O 并还原私有框架接口,解析 Swift 元数据结构,甚至通过版本 diff 观察系统能力的演进。
工具
Swift Stream IDE - 跨平台 Swift 开发扩展
Swift Stream IDE 是由 Mikhail Isaev 开发的功能强大的 VS Code 扩展,旨在让开发者能够流畅地构建面向非 Apple 平台的 Swift 项目。它基于 VS Code 的 Dev Containers 扩展,将编译器、依赖与工具链完整封装在 Docker 容器中,实现了真正一致、可移植的跨平台 Swift 开发体验。目前,Swift Stream 已支持多种项目类型,包括 Web(WebAssembly)、服务器(Vapor/Hummingbird)、Android(库开发)、嵌入式(ESP32-C6、树莓派等)等多种项目类型。
在 The Swift Android Setup I Always Wanted 一文中,Mikhail 还演示了如何结合 Swift Stream IDE、swift-android-sdk 与 JNIKit,高效构建 Android 原生库。
容器化开发的优势包括:保持宿主机环境整洁、确保旧项目的可编译性、支持跨平台一致的开发体验,以及可通过 SSH 远程连接到更强大的机器进行开发。
AnyLanguageModel - 统一 Swift 大模型开发范式
或许许多开发者不会在第一时间使用 WWDC 2025 上推出的 Foundation Models 框架,但大多数人都对它的 API 印象深刻——这一框架显著简化了与大模型的交互流程,并充分发挥了 Swift 语言特性。
Mattt 开发的 AnyLanguageModel 实现了与 Foundation Models 框架完全兼容的 API:只需将 import FoundationModels 换成 import AnyLanguageModel,就能在不改动上层业务代码的前提下,接入多家云端及本地模型后端(OpenAI、Anthropic、Ollama、llama.cpp、Core ML、MLX 以及 Foundation Models)。此外,该库还利用 Swift 6.1 的 Traits 特性,可按需引入重依赖,从而显著降低二进制体积并提升构建速度。
Metal Lab - 基于 Apple Metal API 生态的中文图形学社区
在中文互联网上,关于 Metal 的教程资源非常稀少,尽管 Apple 官方提供了详尽的文档和示例代码,但这些文档对于国内开发者而言往往语言晦涩、结构复杂,缺乏通俗易懂的入门指导,初学者常常感到难以上手。Metal Lab 提供的教程文档旨在填补这一空白,为中文开发者提供一份系统性、易懂、循序渐进的 Metal 入门资料,帮助他们从零开始掌握 Metal 编程的精髓。无论是游戏开发、图形渲染,还是计算机视觉应用,这都是一份值得收藏的中文资源。
往期内容
- Swift 官方发布 Android SDK - #108
- 去 Apple Store 修手机 - #107
- 高通收购 Arduino:历史的轮回 - #106
- Sora 2:好模型,但未必是好生意 - #105
THANK YOU
如果你觉得这份周报或者我的文章对你有所帮助,欢迎 点赞 并将其 转发 给更多的朋友。
📮 想持续关注 Swift 技术前沿?
每周一期《肘子的 Swift 周报》,为你精选本周最值得关注的 Swift、SwiftUI 技术文章、开源项目和社区动态。
- 📬 在 weekly.fatbobman.com 免费订阅
- 💬 加入 Discord 与中文 Swift 开发者深入交流
- 📚 访问 fatbobman.com 查看数百篇深度原创教程
一起构建更好的 Swift 应用!🚀