轉(zhuǎn)載: Swift ABI 穩(wěn)定對我們到底意味著什么
Swift 社區(qū)最近最重大的新聞應(yīng)該就是 ABI 穩(wěn)定了。這個話題雖然已經(jīng)討論了有一陣子了,但隨著 Xcode 10.2 beta 的迭代和 Swift 5 的 release 被提上日程,最終 Swift ABI 穩(wěn)定能做到什么程度,我們開發(fā)者能做些什么,需要做些什么,就變成了一個重要的話題。Apple 在這個月接連發(fā)布了 ABI Stability and More 和 Evolving Swift On Apple Platforms After ABI Stability 兩篇文章來闡述 Swift 5 發(fā)布以后 ABI 相關(guān)的內(nèi)容所帶來的改變。雖然原文不是很長,但是有些地方上下文沒有說太清楚,可能不太容易理解。本文希望對這個話題以問答的形式進行一些總結(jié),讓大家能更明白將要發(fā)生的事情。
我是一個 app 開發(fā)者,Swift 5 發(fā)布以后會怎么樣?
簡單說,安裝 Xcode 10.2,然后正常遷移就可以了,和以往 Swift 3 到 Swift 4 需要做的事情差不多。單論 Swift 5 這個版本,不會對你的開發(fā)造成什么影響,直到下一個版本 (比如 Swift 5.1) 之前,你幾乎不需要關(guān)心 ABI 穩(wěn)定這件事。關(guān)于下個 Swift 版本,我們稍后會提到這件事情。
我還是想知道什么是 ABI 穩(wěn)定?
就是 binary 接口穩(wěn)定,也就是在運行的時候只要是用 Swift 5 (或以上) 的編譯器編譯出來的 binary,就可以跑在任意的 Swift 5 (或以上) 的 runtime 上。這樣,我們就不需要像以往那樣在 app 里放一個 Swift runtime 了,Apple 會把它弄到 iOS 和 macOS 系統(tǒng)里。
所以說 app 尺寸會變???
是的,但是這是 Apple 通過 App Thinning 幫我們完成的,不需要你操心。在提交 app 時,Apple 將會按照 iOS 系統(tǒng)創(chuàng)建不同的下載包。對于 iOS 12.2 的系統(tǒng),因為它們預裝了 Swift 5 的 runtime,所以不再需要 Swift 的庫,它們會被從 app bundle 中刪掉。對于 iOS 12.2 以下的系統(tǒng),外甥打燈籠,照舊。
一個新創(chuàng)建的空 app,針對 iOS 12.2 打包出來壓縮后的下載大小是 26KB,而對 iOS 12.0 則是 2.4MB。如果你使用了很多標準庫里的東西,那這個差距會更大 (因為沒有用到的標準庫的符號會被 strip 掉),對于一個比較有規(guī)模的 app 來說,一般可以減小 10M 左右的體積。
還有什么其他好處么?
因為系統(tǒng)集成了 Swift,所以大家都用同一個 Swift 了,app 啟動的時候也就不需要額外加載 Swift,所以在新系統(tǒng)上會更快更省內(nèi)存。當然啦,只是針對新系統(tǒng)。
另外,對于 Apple 的工程師來說,他們終于能在系統(tǒng)的框架里使用 Swift 了。這樣一來,很多東西就不必通過 Objective-C wrap 一遍,這會讓代碼運行效率提高很多。雖然在 iOS 12.2 中應(yīng)該還沒有 Swift 編寫的框架,但是我們也許能在不久的將來看到 Swift 被 Apple 自己所使用。等今年 WWDC 的消息吧。
我還想用一段時間的 Xcode 10.1,不太想這么快升級
Xcode 10.1 里的是 Swift 4.2 的編譯器,出來的 binary 不是 ABI 穩(wěn)定的,而且必定打包了 Swift runtime。新的系統(tǒng)發(fā)現(xiàn) app 包中有 Swift runtime 后,就會選擇不去使用系統(tǒng)本身的 Swift runtime。這種情況下一切保持和現(xiàn)在不變。舊版本的 Xcode 只有舊版本的 iOS SDK,所以自然你也沒有辦法用到新系統(tǒng)的 Swift 寫的框架,系統(tǒng)肯定不需要在同一個進程中跑兩個 Swift runtime。
簡單說,你還可以一直使用 Xcode 10.1 直到 Apple 不再接受它打包的 app。不過這樣的話,你不能使用新版本 Swift 的任何特性,也不能從 ABI 穩(wěn)定中獲得任何好處。
我升級了 Xcode 10.2,但是還想用 Swift 4 的兼容模式,會怎么樣?
首先你需要弄清楚 Swift 的編譯器版本和語言兼容版本的區(qū)別:
| 編譯器版本 | 語言兼容版本 | 對應(yīng)的 Xcode 版本 |
|---|---|---|
| Swift 5.0 | Swift 5.0, 4.2, 4.0 | Xcode 10.2 |
| Swift 4.2 | Swift 4.2, 4.0, 3.0 | Xcode 10.0, Xcode 10.1 |
| 更多歷史版本 … |
同一個 Xcode 版本默認使用的編譯器版本只有一個 (在你不更換 toolchain 的前提下),當我們在說到“使用 Xcode10.2 的 Swift 4 兼容模式”時,我們其實指的是,使用 Xcode 10.2 搭載的 Swift 5.0 版本的編譯器,它提供了 4.2 的語法兼容,可以讓我們不加修改地編譯 Swift 4.2 的代碼。即使你在 Xcode 10.2 中選擇語言為 Swift 4,你所得到的二進制依然是 ABI 穩(wěn)定的。ABI 和你的語言是 Swift 4 還是 Swift 5 無關(guān),只和你的編譯器版本,或者說 Xcode 版本有關(guān)。
多提一句,即使你選擇了 Swift 4 的語言兼容,只要編譯器版本 (當然,以及對應(yīng)的標準庫版本) 是 5.0 以上,你依然可以使用 Swift 5 的語法特性 (比如新增加的類型等)。
看起來 ABI 穩(wěn)定很美好,那么代價呢?
Good question! 我們在第一個問題里就提到過,一切都會很美好,直到下一個版本。因為 Swift runtime 現(xiàn)在被放到 iOS 系統(tǒng)里了,所以想要升級就沒那么容易了。
在 ABI 穩(wěn)定之前,Swift runtime 是作為開發(fā)工具的一部分,被作為庫打包到 app 中的。這樣一來,在開發(fā)時,我們可以隨意使用新版本 Swift 的類型或特性,因為它們的版本是開發(fā)者自己決定的。不過,當 ABI 穩(wěn)定后,Swift runtime 變?yōu)榱擞脩粝到y(tǒng)的一部分,它從開發(fā)工具,變?yōu)榱诉\行的環(huán)境,不再由我們開發(fā)者唯一決定。比如說,對應(yīng) iOS 13 的 Swift 6 的標準庫中添加了某個類型 A,但是在 iOS 12.2 這個只搭載了 Swift 5 的系統(tǒng)中,并沒有這個類型。這意味著我們需要在使用 Swift 的時候考慮設(shè)備兼容的問題:如果你需要兼容那些搭載了舊版本 Swift 的系統(tǒng),那你將無法在代碼里使用新版本的 Swift runtime 特性。
這和我們一直以來適配新系統(tǒng)的 API 時候的情況差不多,在 Swift 5 以后,我們需要等到 deploy target 升級到對應(yīng)的版本,才能開始使用對應(yīng)的 Swift 特性。這意味著,我們可能會需要寫一些這樣的兼容代碼:
// 假如 Swift 6.0 是 iOS 13.0 的 Swift 版本
if #available(iOS 13.0, *) {
// Swift 6.0 標準庫中存在 A
let a = A()
} else {
// 不存在 A 時的處理
}
對于“新添加的某個類型”這種程度的兼容,我們可以用上面的方式處理。但是對于更靠近語言層面的一些東西 (比如現(xiàn)在已有的 Codable 這樣的特性),恐怕適配起來就沒有那么簡單了。在未來,Deployment target 可能會和 Swift 語言版本掛鉤,新的語言特性出現(xiàn)后,我們可能需要等待一段時間才能實際用上。而除了那些純編譯期間的內(nèi)容外,任何與 Swift runtime 有關(guān)的特性,都會要遵守這個規(guī)則。
可以像現(xiàn)在一樣打包新版本的 Swift runtime 到 app 里,然后指定用打包的 Swift 版本么
不能,對于包含有 Swift runtime 的系統(tǒng),如果運行的 binary 是 ABI 穩(wěn)定的,那么就必須使用系統(tǒng)提供的 Swift。這里的主要原因是,Apple 想要保留使用 Swift 來實現(xiàn)系統(tǒng)框架的可能性:
- 如果允許兩個 Swift runtime (系統(tǒng)自帶,以及 app 打包的),那么這兩個運行時將無法互相訪問,app 也無法與系統(tǒng)的 Swift 框架或者第三方的 ABI 穩(wěn)定的框架進行交互。
- 如果允許完全替換 Swift runtime,系統(tǒng)的 Swift 框架將執(zhí)行用戶提供的 Swift 標準庫中的代碼,這將造成重大的安全隱患。
有任何可能性讓我能無視系統(tǒng)版本,去使用 Swift 的新特性么
有,但是相對麻煩,很大程度上也依賴 Apple 是否愿意支持。如果你還記得 iOS 5.0 引入 ARC 時,Apple 為了讓 iOS 4.3 和之前的系統(tǒng)也能使用 ARC 的代碼,在 deployment target 選到 iOS 4.3 或之前時,會用 static link 的方式打包一個叫做 libarclite 的庫,其中包含了 ARC 所需要的一些 runtime 方法。對于 ABI 穩(wěn)定后的 Swift,也許可以采用類似做法,來提供兼容。
這種做法在感覺上和 Android 的 Support Library Packages 的方式類似,但是 Apple 似乎不是很傾向于提供這樣的官方支持。所以之后要看有沒有機會依靠社區(qū)力量來提供 Swift 的兼容支持了。
不能第一時間用上新的語言特性,必然會打擊大家進行適配和使用新特性的積極性,也勢必會影響到語言的發(fā)展和快速迭代,可以說這一限制是相當不利的。
所以,對于一般的 app 開發(fā)者來說,ABI 穩(wěn)定其實就是一場博弈:你現(xiàn)在有更小的 app 尺寸,但是卻被限制了無法使用最新的語言特性,除非你提升 app 的 depolyment target。
我是框架開發(fā)者,ABI 穩(wěn)定后我可以用 binary 形式來發(fā)布了么?
還不能。ABI 穩(wěn)定是使用 binary 發(fā)布框架的必要非充分條件??蚣艿?binary 在不同的 runtime 是兼容了,但是作為框架,現(xiàn)在是依靠一個 .swiftmodule 的二進制文件來描述 API Interface 的,這個二進制文件中包含了序列化后的 AST (更準確說,是 interface 的 SIL),以及編譯這個 module 時的平臺環(huán)境 (Swift 編譯器版本等)。
ABI 穩(wěn)定并不意味著編譯工具鏈的穩(wěn)定,對于框架來說,想要用 binary 的方式提供框架,除了 binary 本身穩(wěn)定以外,還需要描述 binary 的方式 (也就是現(xiàn)在的 swiftmodule) 也穩(wěn)定,而這正在開發(fā)中。將來,Swift 將為 module 提供文本形式的 .swiftinterface 作為框架 API 描述,然后讓未來的編譯器根據(jù)這個描述去“編譯”出對應(yīng)的 .swiftmodule作為緩存并使用。
這一目標被稱為 module stability,當達到 module stability 后,你就可以使用 binary 來發(fā)布框架了 (當然,這種 binary 框架只支持帶有 ABI 穩(wěn)定的 Swift runtime 的平臺,也就是 iOS 12.2 及以上)。
能總結(jié)一下 ABI 穩(wěn)定,或者展望一下未來么?
ABI 穩(wěn)定最大的受益者應(yīng)該是 Apple,這讓 Apple 在自己的生態(tài)系統(tǒng)中,特別是系統(tǒng)框架中,可以使用 Swift 來進行實現(xiàn)。在我看來,Swift ABI 穩(wěn)定為 Apple 開發(fā)平臺的一場革命奠定了基礎(chǔ)。在接下來的幾年里,如果你還想要關(guān)注 Apple 平臺,可能下面幾件事情會特別重要:
- Apple 什么時候發(fā)布第一個 Swift 寫的系統(tǒng)框架
- Apple 什么時候開始提供第一個 Swift only 的 API
- Apple 什么時候開始“鎖定” Objective-C 的 SDK,不再為它增加新的 API
- Apple 什么時候開始用 Swift 特性更新現(xiàn)有的 Objective-C SDK
這些事情也許會在未來幾年陸續(xù)發(fā)生。面對微軟從 Win32 API 向 .Net 一路遷移,到今天的 UWP (Universal Windows Platform),Google 來勢洶洶的 Fuchsia 和 Dart,Swift 是 Apple 唯一能與它們抗衡的答案。相比于微軟提供的泛型和并行編程模型,Google 的 Flutter 的跨平臺的先天優(yōu)勢,Apple 平臺基于 Objective-C 的 API 的易用性已然被拋開很遠。雖然 Apple 在 2014 年承諾過依然維護 Objective-C,但是經(jīng)過 Swift 這五年的發(fā)展,隨著 Swift ABI 的穩(wěn)定,什么時候如果 Objective-C 成為了繼續(xù)發(fā)展的阻礙,相信 Apple 已經(jīng)有足夠的理由將它拋棄。
作為 Apple 平臺的從業(yè)者,我們也許正處在另一個時代變革的開端。