Swift 與 Objective-C

[Swift 深入解析 #9] Swift ABI 穩定性:2019 年 App 容量縮小的原因

2019 年 Swift 5 與 iOS 12.2 發布後,App 容量縮小是 ABI 穩定性帶來的結果。本文整理 Swift 執行階段從每個 App 搭載移至 OS 的過程,以及模組穩定性與 @frozen 的取捨。

閱讀 7 分鐘
[Swift 深入解析 #9] Swift ABI 穩定性:2019 年 App 容量縮小的原因 封面圖

2019 年春天,Swift 5 隨 iOS 12.2 發布後,奇怪的事情發生了。什麼都沒做,App 容量卻縮小了好幾 MB。 Swift ABI Stability and More

這是接續上一篇文章 Swift 深入解析 #8 的內容。

秘密就在版本資訊中乾巴巴的一行字:達成 ABI 穩定性。

Swift 系列的最後一篇,要完整說明這起事件:ABI 是什麼、為什麼花了 5 年,以及它促成了什麼。

這是語言歷史與底層結構交會的地方,很適合作為系列的收尾主題。

ABI 是什麼 — 二進位檔之間的約定

大家都知道 API,那是原始碼層級的約定:函式叫什麼、引數有哪些。

ABI(Application Binary Interface)是更底層的、已編譯二進位檔之間的約定。

它包含呼叫函式時要把引數放進哪些暫存器、struct 如何配置在記憶體中(版面配置篇看過的那些尺寸),以及如何命名符號(名稱修飾)和在哪裡尋找中繼資料。

為什麼這項約定很重要?因為不同時間、使用不同編譯器建置的兩個二進位檔必須能一起運作。

App 與 OS 內建函式庫的關係正是如此。如果 ABI 隨版本變動,使用 Swift 5.0 建置的 App 就無法與 Swift 5.5 執行階段溝通。 Swift ABI Stability and More

Swift 早期確實如此。ABI 每個版本都會變更,因此每個 App 都必須完整攜帶自己使用版本的 Swift 執行階段與標準函式庫。

每個 App 都多了數 MB 的重複負擔,OS 也無法在自己的框架中使用 Swift,因為系統框架還必須與未來的 App 溝通,而當時沒有這項保證。

Swift 5 的 ABI 穩定性宣告凍結了這項約定。呼叫慣例、型別版面配置與名稱修飾都已確定,之後的版本會在遵守這項約定的前提下演進。 Swift ABI Stability and More

標準函式庫隨即搬進 OS(從 App 移除後,容量便縮小)。Apple 也因此能以 Swift 建立 SwiftUI 等系統框架。

2019 年的容量縮減,其實是這門語言走向成熟的訊號。 Swift ABI Stability and More

為什麼花了 5 年 — 凍結的重量

面對「為什麼不早點凍結」的疑問,必須先看看凍結的成本。確定 ABI 就代表連當時的設計錯誤也要永遠承擔。

一旦承諾了版面配置與規約,只要既有二進位檔存在於世上,就不能再修改。

回想 Swift 1~4 時期有多麼劇烈變動。語法幾乎每個版本都重新翻修。如果當時就凍結,現在的 Swift 早已被關進初期設計的牢籠。 Swift ABI Stability and More

我們等到泛型實作穩定、值型別版面配置策略經過驗證,也等了 Evolution 流程(哲學篇第 4 集)整理重大設計爭論,前後就是 5 年。

看看 C++ 因數十年的 ABI 慣性而否決改進方案的案例,就能理解這份謹慎的價值。

每個 App 背負的 Swift 執行階段背包搬到 OS 共用支柱的前後對照
每個 App 背負的執行階段背包,已搬到 OS 共用支柱

第二項約定 — 模組穩定性與函式庫演進

不過,只有 ABI 穩定性仍少了一塊拼圖:二進位框架的發布。

Swift 5.0 以前的編譯器會以名為 swiftmodule 的二進位格式交換模組介面,但它受限於編譯器版本。 Swift ABI Stability and More

Xcode 一升級,所有已發布的 SDK 就會全部失效。

Swift 5.1 的模組穩定性解決了這個問題。它引入以文字為基礎的穩定介面檔案(.swiftinterface),因此能讀取使用其他版本編譯器建置的框架。 Swift ABI Stability and More

以 XCFramework 發布 SDK 的生態系(付款、分析、地圖 SDK)便建立在這項基礎上。

與此配套的概念是函式庫演進模式。這個選項會以「之後即使新增儲存屬性,也不會破壞既有 App」的方式建置框架,但代價很有意思。

此模式下的 public struct 會成為版面配置尚未確定的 resilient type。用戶端無法在編譯時期得知其大小,必須支付間接存取的成本。

這正是版面配置篇「知道大小就會更快」的反命題。

因此演進模式提供了 @frozen 這個出口:「凍結此型別的版面配置,但允許直接存取。」標準函式庫中的 Int 與 Optional 之所以是 @frozen,正是這個原因。

對 App 開發者而言,實際意義如下:App 目標與原始碼發布套件(大多數 SwiftPM 套件)不需要此模式,開啟反而會吃虧。

只有以二進位檔發布 SDK 的一方才需要開啟。問題「BUILD_LIBRARY_FOR_DISTRIBUTION 是什麼?」的答案就在這段。

收尾 — 貫穿整個系列的一個故事

ABI 成為 Swift 系列最後一篇是有原因的。一路介紹的概念,全都在這個節點匯合。

值型別的版面配置(值篇、版面配置篇)已凍結,因此 struct 能跨越二進位邊界。witness table(分派篇)的格式已確定,因此協定成為框架 API。

而 Evolution 流程(哲學篇第 4 集)讓設計成熟,也讓我們有信心將其凍結。

以型別確保安全(Optional、ARC、Sendable),明確標示成本(unsafe、any、@unchecked),再以階梯呈現複雜度(Progressive Disclosure)。

這些原則從語法層一路貫穿到二進位層,始終保持一致;這就是整個系列想傳達的故事。

Swift 至今仍在 Evolution 論壇上打造下一階梯。希望這個系列能成為你自行理解這些變化的地圖,我們就此收尾。

對比可演進框架與 @frozen 凍結結構存取速度的插圖
是演進的彈性,還是凍結的速度?@frozen 就是那個開關

總結

  • ABI 是二進位檔之間的約定(呼叫慣例、版面配置、名稱修飾),並在 Swift 5(2019 年)凍結。多虧如此,標準函式庫搬進 OS、App 容量縮小,Apple 也能以 Swift 建立 SwiftUI。
  • 凍結花了 5 年,是因為這項決定代表要永遠承擔設計錯誤。那段時間是在等待泛型、版面配置與 Evolution 流程成熟。
  • Swift 5.1 的模組穩定性(.swiftinterface)開啟了二進位框架生態系(XCFramework)。
  • 函式庫演進模式以「框架即使演進,App 也不會損壞」換取間接存取成本,而 @frozen 就是出口。對 App 目標而言,這是不必要的選項。
  • 系列結論:Swift 將安全型別化、成本明確化、複雜度階梯化的原則,從語法一致延伸到二進位檔。 Swift ABI Stability and More

來源與確認標準

  • Swift ABI Stability and More — Swift.org · 官方發布 · 確認日期 2026-08-17 · 依據:Swift 5 ABI 穩定性、OS 搭載執行階段與 App 容量變化

延伸閱讀

Swift 深入解析系列