不管你是否主力 Swift, 這些事情你均可以瞭解一下

Swift 再等等?個人答案是:快上車 - 簡書git

主力 Swift 或許真的要等一等 - 知乎專欄 程序員

上一週有兩篇文章, 分別討論了你們在現階段到底該不應用 Swiftgithub

在這裏我不是想給出一個答案該不應用 Swift, 只是想聊一聊我對於 Swift 的理解.objective-c

Swift 能不能取代 Objective-C?

那兩篇文章都討論了一個話題, Swift 到底能不能取代 Objective-C?編程

其實到如今爲止 Swift 離替代 Objective-C 仍是很遙遠,由於 Apple 內部一直在用 Objective-C 來作一些 Framework 的開發,低層也不可能用 Swift 實現swift

— Cyanapi

若是把取代定義爲編寫底層框架的話, 至少以 Swift 3 來講, 毫無疑問是不可能的.數組

首先咱們先去探究一下爲何蘋果會選擇 Objective-C 做爲官方開發語言?

Objective-C 是在 C 的基礎上加上一層面向對象, 在編寫高性能模塊的時候, 能夠直接使用 C, 在編寫對於性能不高的業務模塊時, 就使用原生的 Objective-C.安全

目前蘋果的框架, 底層實現都是使用 C , 而後再套上一層 Objective-C 去暴露外部接口. 這種方式既保證了性能, 又能保證 API 的易用性.app

並且蘋果使用了大量的開源框架, 系統底層不少模塊, 都已經有了開源的基於 C 語言的框架實現, 跟 C 的交互上, Swift 明顯不如 Objective-C 那麼方便.

除開語言生態, 還有一個問題是 Swift 的性能不如 C, Swift 在公佈的時候, 就宣稱運行效率能夠媲美甚至超越 C. 但這是有前提的, 沒有運行時損耗的狀況下 Swift 纔有可能與 C 的運行效率持平.

Swift 的運行時損耗到底來自哪裏

Swift 的運行效率損耗主要來自於 ARC, 內存管理, 運行的時候, 一個對象會不停地進行 retain 和 release, runtime 必須一直 observe 每個對象的 retain count, 當 retain count 達到 0 的時候就釋放這個對象. 而 C 就沒有這個問題, 由於 C 沒有對象, 沒有運行時的損耗.

那解決方式也就很簡單了, 換一種新的內存管理模式就好了(Swift 實際作法是直接引入了一種新模式, 與 ARC 並存).

目前主流的內存管理方式分三種:

  1. 手動: C 語言的 malloc 庫, 特色就是無運行時損耗, 但很差控制釋放內存的時機.
  2. 半自動: Objective-C 和 Swift 的 MRC/ARC, 有運行時損耗, 但基本上可讓程序員不用去考慮內存管理的問題.
  3. 自動的: Java/Go 的 GC. 基本上同上, 但須要在某個時間點去中止全部線程, 釋放內存的時機不可控.

Objective-C 的 MRC 還須要手動去寫 retain/release, 在進化到 ARC 以後, 除了須要在類成員變量聲明的時候, 顯式地聲明是 weak/strong/retain/copy 就能夠了, retain/release 的插入交給編譯器便可, ARC 其實已是實際上的自動化內存管理模式了.

而 Swift 在把指針抽象爲引用類型, 加入 Mutable/Immutable 的概念以後, 就只須要偶爾寫寫 weak 就好了, 惟一須要對於內存管理費心的就是 retain cycle 的問題, 但也比以前省心不少了. 並且隨着 Swift 工具鏈的發展, 這些問題均可以在編譯期或者 Debug 時就暴露出來.

半自動的內存管理, 實際上還有一種, 就是 Rust 的 OwnerShip, 我我的的理解是, 這種方式實際上是 MRC/ARC 的一種延續, 但 MRC/ARC 內存釋放的時機仍是須要在運行時才能知道, 而 Rust 能夠在編譯期就解析出何時能夠釋放掉內存, 從而省略掉 retain/release 的存在, 也不必專門跑一個 runtime 去監測對象的引用計數., 從而達到比 ARC 更高的運行效率

仔細思考一下這種自動化的內存管理模式, 其實都是在把指針分類, 加上 context(上下文), 抽象出來, 暴露給編譯器更多與關於指針的信息, 而不是單純的一個內存地址, 從而讓編譯器能夠分析釋放對象的時機.

Rust 也不例外, 既然要達到比 ARC 更高的運行效率, 那就必然要提供給編譯器更多的指針信息, 所以在指針聲明和傳遞時都須要顯式地聲明全部權, 代碼量也會相應地增多, 對於程序員的要求也會更高.

雖然寫起來比 ARC 更麻煩一點, 但也比 C 那種原始的方式簡單不少, 提供給了 Rust, Swift 這些」現代編程語言」編寫底層程序的可能性.

補充: 學術界對於 GC 的研究已經不少了, 但關於 ARC 的研究仍是不多, ARC 還有很大的進步空間. 甚至說若是能夠在編譯期就檢測到對象實際釋放的時機的話, 就能夠直接省略掉中間的那些 retain/release, 沒必要在運行時再去檢測是否應該釋放掉這一段內存.

Swift 何時會引入這種內存管理模式

在我寫這篇文章的時候, Swift 團隊正式發佈了引入 OwnerShip 的提案(正式方案?), 喵神大大也翻譯了這篇文章, 更多技術細則能夠去看喵神大大的翻譯.

一句話總結: Swift 的團隊但願 Swift 可以進化成爲一門系統編程語言, 因此纔不惜犧牲 ABI 穩定性去加入這個 Feature.

Swift 是爲了取代 Objective-C 而生的嗎

在 Cyan 大大的那篇文章下面, 有這麼一條回覆.

LLVM 之父, Swift 的做者之一 Chris Lattner 在 ATP 的一期訪談裏聊過這件事情, 直接貼原話:

There's a ton of stuff to love about Objective-C, and while there are a few things that are ugly about it, some 「@「 signs and semicolons and other stuff like that, we can make Objective-C better. The question was always: Why not just make Objective-C better? Why don't we just keep evolving Objective-C? Why do we want to face potential disruption in terms of moving the entire development community to something [23:00] new?

We kicked that around for a long time. We talked about both sides and we came to realize that, yes, we can and should make Objective-C better, and we continued to invest in Objective-C. We did things like ARC, for example, which is a major effort, but…

We were talking about, okay, can we just make Objective-C better and can we feature-creep it to the language we want for the fullness of time? Because if we can, that would be much less disruptive to the community. We decided that, yeah, we can move Objective-C a lot closer to what we want so we can get automatic memory management with ARC, for example, but we can't ever take away the problems that lead to Objective-C being unsafe. The fundamental problem was Objective-C was built on top of C. [24:00] C inherently has pointers. It has uninitialized variables. It has array overflows. It has all these problems that even if you have full control of your compiler and tool stack, you just can't fix. To fix dangling pointers, you would have to fix lifetime issues, and C doesn't have a framework to reason about that, and retrofitting that into a compatible way into the system just wouldn't really work.

If you took away C from Objective-C, you couldn't use C arrays on the stack, for example. And if you [24:30] couldn't do that, there's entire classes of applications where the performance just wouldn't be acceptable. We went around, around, around. We said the only way that this can make sense in terms of the cost of the disruption to the community is if we make it a safe programming language: not 「safe」 as in 「you can have no bugs,」 but 「safe」 in terms of memory safety while also providing high performance and moving the programming model forward. That was really kind [25:00] of the ideas that came together to make Swift being worth the investment and being worth being disruptive to the community. A lot of these kinds of pitches and ideas were being held in very small, small, small meetings. Coming out of WWDC 2013 is when we and the executive team decided okay, let's really commit to this, and that’s when the developer-tools [25:30] team came to know about it and really started working hard on it.

— 節選自 Accidental Tech Podcast: Chris Lattner interview

內容有點長, 你們能夠看一下我高亮的部分, 實際上蘋果的團隊也很猶豫, 到底要繼續優化 Objective-C, 仍是應該發明一門新的語言. 最後兩種方式都嘗試一下, 而後 Objective-C 就有了 ARC, 點語法等等新功能.

但最後, 蘋果的團隊發現 Objective-C 這門語言不安全最關鍵的緣由仍是由於它是基於 C 語言的, 它有指針, 它有不徹底初始化的變量, 它會數組越界. 即便蘋果的團隊對於工具鏈和編譯器有完整的控制權, 也沒辦法很好地解決這個問題.

蘋果的團隊想了又想, 反覆思慮以後, 仍是決定打斷整個開發社區, 去建立一門 Safe 的編程語言, 不僅是那種沒有 bug的 Safe, 而是保持安全的同時還能提供高性能的, 推進整個編程範式前進的那種 Safe.

Swift 與 Objective-C 並不是是對立的, 「Objective-C is Great」, Swift 只是蘋果提供的一個 「better option」.

ABI Stability vs. API Stability

關因而否應該主力 Swift 另外一個關鍵的爭論點在於, ABI 不穩定.

由於 Swift 的 ABI 不穩定而放棄 Swift 的人好像特別多. 但是我看到的不少文章都沒有提到到底 ABI 穩定對於咱們應用開發者表明着什麼? ABI 與 API 又有什麼區別?

ABI (Application Binary Interface)

在計算機中,應用二進制接口(英語:application binary interface,縮寫為 ABI)描述了應用程序(或者其餘類型)和操做系統之間或其餘應用程序的低級接口。

… ABI不一樣於應用程序接口(API),API定義了源代碼和庫之間的接口,所以一樣的代碼能夠在支持這個API的任何系統中編譯,然而ABI容許編譯好的目標代碼在使用兼容ABI的系統中無需改動就能運行。

zh.wikipedia.org/wiki/應用二進制接…

ABI 主要是描述程序跟操做系統之間的低級接口, 說白了就是Swift 二進制程序與系統或者其它程序交互時會調用的接口, 通常這部分都是由編譯器去處理, 除非咱們進行很底層的開發, 或者是想要 hack 編譯過程(例如把 Swift 編譯到 JavaScript) 纔會須要去考慮這方面的東西.

ABI 的不穩定會形成如下結果:

  1. 打包 Swift 程序時, 必須嵌入一個 Swift 標準庫.咱們每次打包應用時, 都須要嵌入一個 Swift 的標準庫, 由於系統不知道咱們使用程序時用的 ABI 是哪一個版本, 因此必須沒辦法在系統內部內置一套標準庫. 用過 pyenv, rvm 或者 nvm 的人就大概知道這裏的過程.
  2. 第三方 SDK 開發困難. 你的應用與第三方 SDK 使用的 ABI 版本若是不一樣就會出現問題, 例如說 Swift 2和 Swift 3打包出來的庫就沒辦法互相調用. 非要支持的話, Swift 每出一個版本就須要跟着打包一個 SDK, 並且以前的 SDK 沒辦法向後兼容.

ABI 的穩定到底意味着什麼

說明完了 ABI 是什麼, 以及 ABI 不穩定會形成什麼.

那 ABI 穩定對咱們有什麼實際意義? Chirs 在 ATP 裏討論過這個問題, 繼續貼原話:

Another part of it is that ABI stability is super-important, but it's not as important as people think it is for application developers. It's really important to Apple, [51:30] but what we realized in the Swift 3 timeframe is that the thing app developers would benefit from the most was actually source stability. Who actually wants their application to be broken when they get a new version of Xcode? Really nobody, right?

ABI 穩定超級重要, 不過對於應用開發者來講, 並無你們想象的那麼重要. 可是對於蘋果來講很重要. 咱們相信在 Swift 3 以後, 應用開發者受益最多的仍是代碼穩定(API Stability), 誰願意升級了一下 Xcode 就運行不了本身的程序呢?

ABI 的穩定對咱們來講真的沒有那麼重要, 大廠開發 SDK 也只要選擇 Objective-C 就好了(因此不能用 Swift 纔是痛苦的地方?). 再給點力的話, 底層使用 Objective-C 實現, 用 Swift 負責暴露外部接口也行(例如 Instagram 開源的 IGListKit), Swift 版本遷移的工做就會大幅減小了. ABI 不穩定最痛苦的實際上是蘋果的底層開發人員, 他們必須實時去更新框架對外的接口, 想辦法讓官方框架去兼容不一樣版本的 Swift.

補充: 寫這篇文章的時候, 柏學網翻譯了 Swift 官方關於 ABI 穩定的聲明, 你們能夠去看看

API 穩定還會是問題嗎

Halfway through the release, we pivoted and source stability became the goal, so I'm really excited that when Swift 3.1 or Swift 4 comes out that it's still going to be able to build [52:00] Swift 3 code, and even if there are minor changes that need to be made for one reason or another, that you can upgrade and you have great compatibility with your old code and you don't have to start the migrator before you can do anything. So it's going to be a great improvement for people's lives.

Swift 4的開發途中, 咱們定下了一個目標, 不管是在 Swift 3.1 仍是 Swift 4 裏, 都必須能夠編譯 Swift 3的代碼(編譯器提供相應的編譯模式)

API 不穩定致使的代碼遷移, 可能 Swift 1 到 Swift 2 對於你們的衝擊太大, 因此你們纔會有那麼深的怨念, 我沒有經歷過那一段日子沒有發言權.

但 Swift 2 到 Swift 3 的遷移我是經歷過的, 公司項目剛起步, 一萬多行代碼左右, 自動轉換加上一個晚上我就讓程序成功跑起來了, 隨後一個星期修修 bug, 適配一下新的 Feature 也就徹底過分過去了, 後來陸陸續續看了 Enjoy, Airbnb 等等關於 Swift 遷移過程的講述, 過程其實也沒有很痛苦. 但 CoreGraphic 等框架的 Swift 化帶來的麻煩可能會更多一點, 代碼耦合度過高的項目可能會在這裏陷得很深.

Swift 3 以後會好不少, Swift 4的編譯器提供了 Swift 3的編譯模式, 至少咱們能夠慢慢地去遷移咱們的代碼, 而不是一升級 Xcode 就連程序也跑不起來.

API 以後確定還會改的, 但其實從 Swift 2 到 Swift 3 的過程裏, 我以爲不少原則性的東西其實已經穩定下來的, 接下來的改動要麼就是很小, 要麼就是特別有規律性, 遷移的時候花點時間去看看第三方發的遷移指南, 就能夠很平穩地遷移過去了.

一句話總結: ABI 不穩定對於咱們應用開發者的影響並無那麼大, API 以後雖然會變, 但以後確定會給你充足的遷移時間

Swift 之我見

說了這麼多, 但願你們如今能夠理解 Swift 的團隊究竟是基於什麼樣的緣由, 才作出了各類決策, 才演變出瞭如今的 Swift.

最後, 我想聊聊本身對於 Swift 的看法.

Swift 目前的問題

代碼穩定, 其實都是小事情, 遷移, 幾十萬行代碼, 分配給全部人, 最多也就是一個星期的事情. Swift 的開發者都很積極, 主流的第三方框架基本上兩個星期內都能更新到最新的版本, 我用的庫 75% 都從 beta 時期就開始跟進 Swift 的更新.

Swift 3 最大的問題我以爲仍是工具鏈不穩定

  • 增量編譯作的很差. 編譯隨時 Segment Fault, 必須 clean 一次才行.

  • 超長的編譯時間. 每次編譯出錯, clean 以後可能須要編譯七八分鐘, 以前我記得還有人總結了一份什麼樣的語法會致使編譯時間變長的列表, 爲了編譯時間縮短而卻強行改變代碼應有的樣子, 我以爲很不值得.
    我採用的解決方式就是把底層模塊抽出來, 獨立成一個框架, 使用 Carthage 去進行包管理, 所有編譯成靜態庫, debug 編譯的時候, 只要連接上去就好了, 大大減小編譯時間. (順帶一說, Carthage 是用 Swift 寫的)

  • 代碼高亮隨時崩, 代碼補齊幾乎沒有. Xcode 很容易變白板, 我我的而言發生狀況很少, 一天能趕上個兩三次左右, 可是代碼補齊就真心是徹底沒有, 天天基本上都是盲打, 只有像是 UICollectionElementKindSectionFooter 這種纔會等等代碼補齊. (補充一下, AppCode EAP 對於 Swift 3的支持異常的好, 補齊跟高亮都可以很好地知足平常需求, 個人 Air 8g 內存就能跑的很好)

這兩個問題雖然很小很不起眼, 但對我平常工做影響是最大的.

以前 Chris Lattner 離開蘋果加入特斯拉的消息你們應該都知道, 但 Chris 依舊保留本身在 Swift 開發小組的位置, 而實際上 Chris 在蘋果也只有很小一部分時間分配給 Swift(LLVM 對於這個世界影響更大一點), 接任的 Ted, 實際上也是以前實際上的 Swift 開發小組組長, 他以前也是 Rust 的主要開發者之一, 初版的 Clang 靜態分析器也是 Ted 一我的擼出來的.

Chris 平時主要負責提一些」天馬行空」的想法, 打亂掉開發小組的計劃, Ted 負責把這些想法落地.

Ted 我的更傾向於優化編譯, 提升開發體驗, 比起 ABI 穩定優先級更高, 但具體決策仍是得根據具體狀況去決定.

雖然開發體驗對我來講也很重要, 很難割捨, 但我隱約感受不管是外部, 仍是蘋果內部, 留給 Swift 開發團隊的時間可能不會特別多了, 加緊開發功能性的東西, 趕快穩定 ABI 可能會更加劇要.(只是我的感受, 單純的我的感受)

Swift 目前的熱度主要仍是由於 iOS 平臺的強勢, 繼續增強什麼語法糖, 優化開發體驗, 最終也只會把 Swift 坑進 iOS 裏, 只有讓 Swift 變得更強大, 可以在更多領域有所發揮, 才能反哺 Swift, 讓 Swift 變成一門偉大的語言.

Swift 很 Apple

Swift 吸取了不少語言的特色, 以致於各類不一樣語言的開發者寫 Swift 的時候都會以爲特別熟悉特別親切. Chris 說 Swift 並非想成爲某一門語言的增強版, 也不是在模仿哪一門語言, Swift 只是想作到最好, 而想要作到最好就必須去吸取現有語言的優勢, 經過某種方式去把它們糅合到一塊兒. 相似的一句話, 喬布斯也說過, 「咱們不是刻意在模仿誰, 只是想作到最好, 若是作到最好須要學習別人的一些地方, 那就學習唄」, 這些都只是過程罷了, Best 纔是結果.

Swift 的 ABI 不穩定, 影響最大的實際上是蘋果本身, 但由於 Swift 想成爲更好的語言, 因此一再拖延. 延期, 回爐再造, 而後再拿出一個最好的」做品」, 就像蘋果的其它做品.

Swift 還很不成熟, 各類意義上都不成熟, 須要作的事情不少, 泛型系統, 內存管理模型, 性能, 異步模型, POP 的探索, 編譯的優化, ARC 的優化, 函數派發機制, 字符串處理, 更好的異常處理……

結語

Swift 對我來講是一種浪漫, 一種對於蘋果文化的崇尚.

推薦閱讀:

相關文章
相關標籤/搜索