Swift 5.3 又更新了什麼新奇爽快的語法?

Swift 在 WWDC14 正式發佈到 2019,經過 5 年的不斷迭代,這其中經歷了標準庫變動,語法的增減。首先使用 Swift 作為開發語言的開發者們都苦不堪言,戲稱《Swift 從入門到重學》,幾乎每一年 Swift 都會迎來比較大的改動,甚至 API 都發生了變化。

WWDC 19 蘋果發佈了 Swift 5.0,蘋果終於宣佈 Swift 的 ABI 穩定。這標誌著 Swift 這門語言已經趨於穩定,在 2019 至 2020 的迭代中,Swift 5.2 也做到了模塊穩定,之前的大修大改已經不會在出現了。

Swift 發展里程碑

Swift 里程碑.png

有意思的是,在 WWDC16 中有一頁 PPT 寫下了 Goals for Swift 3:

Develop an open community

Portability to new platforms

Get the fundamentals right

Optimize for awesomenss

如今已經 2020 年,再回頭看這些目標,Swift 5.3 幾乎完全實現了。Swift 可謂一直不忘初心,朝著認為正確的方向不斷的努力。

語法的不斷成熟

每年 WWDC 比較期待的一個點就是看看 Swift 又加了一些什麼新奇爽快的語法。我先列舉一下 Swift 5.3 新增的語法:

  • [SE-0249] KeyPath as Function
  • [SE-0279] Multiple trailing closure
  • [SE-0281] Type-based program entry point (@main)
  • [SE-0266] Synthesized comparable conformation for enum types
  • [SE-0269] Increased availability of implicit self in closure
  • [SE-0276] Multi-pattern catch clauses
  • [SE-0280] Enum cases as protocol witnesses
  • [SE-0267] Where clauses on contextually generic declarations
  • [SE-0270] Collection operations on noncontiguous elements
  • [SE-0264] Standard library preview package
  • [SE-0253] Callable values of user-defined nominal types
  • [SE-0263] String initializer with access to uninitialized storage

上面列舉的 12 個語法改動,有興趣的同學可以到 swift-evolution 去查看詳細的內容。其中比較有意思的幾個改動就是 [SE-279],[SE-281]和[SE-0269],我們來細細評味一下。

▐ Design for SwiftUI

[SE-279] Multiple trailing closure 多重尾閉包這個新特性算是一個非常大的改動。這個特性的出現影響了 Swift 非常重要的地方,ABI 設計。先來幾個官方的例子:

// 1. Single closure argument -> trailing closure
UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
}
// 2. With trailing closure
UIView.animate(withDuration: 0.3, animations: {
  self.view.alpha = 0
}) { _ in
  self.view.removeFromSuperview()
}
// 3. Multiple closure arguments -> no trailing closure
UIView.animate(withDuration: 0.3, animations: {
  self.view.alpha = 0
}, completion: { _ in
  self.view.removeFromSuperview()
})
// 4. Multiple trailing closure arguments
UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
} completion: { _ in
  self.view.removeFromSuperview()
}

上面的代碼中 2 的情況是經常出現的,尾閉包的含義就不夠明確,以前最佳的方式應該為 3,但是兩個閉包被套在一個小括號裡,使得括號多重嵌套,可讀性下降。為了解決這個問題,蘋果使用了第 4 中方法--多重尾閉包。可以從代碼看出可讀性得到了很大的提升。

這一看似優雅的設計其實引入了很多語言的複雜度,有了這個特性你甚至可以寫出類似下面的代碼,看上去就像是創造了一個 if-else 語句,但其實它是一個函數。

func when<T>(
  _ condition: @autoclosure () -> Bool,
  then: () -> T,
  `else`: () -> T
) -> T {
  condition() ? then() : `else`()
}
// using syntax
when(2 < 3) {
  print("then")
} else: {
  print("else")
}
// equivalent to:
when(2 < 3, then: { print("then") }, else: { print("else") })

這就對 SDK 的開發者提出了更高的要求,需要小心的使用這個特性來設計 API,防止這個特性被濫用導致代碼的可讀性下降,甚至造成歧義。蘋果在 WWDC20 中也強調了這一點。

還有兩個特性其實很簡單,[SE-0281] 是 @main 來標記程序入口,[SE-0269] 是讓開發者在特定的情況下不需要再寫多餘的 self.。

蘋果推出了這幾個語言特性,就是為了讓戰略性的項目 SwiftUI 的 API 更加簡潔明瞭。可以看下面的例子:

@main // <- @main
struct MyApp: App {
    var body: Scene {
        WindowGroup {
            Text("Hello World!")
        }
    }
}
//------
Gauge(value: acidity, in: 3...10) {
    Image(systemName: "drop.fill")
} currentValueLabel: { // <- multiple trailing closure
    Text("\(acidity, specifier: "%.1f")")
} minimumValueLabel: {
    Text("3")
} maximumValueLabel: {
    Text("10")
}
//------
struct ContentView : View {
    var landmark: Landmark
    var body: some View {
        Button(action: {
            landmark // <- no self.
        }) {
            Text("Button")
        }
    }
}

蘋果也不是第一次為了 SwiftUI 改 Swift 的語法,[SE-0255] Implicit returns from single-expression functions 就是為了讓 SwiftUI 的 body 不用寫 return,強化 DSL 風格。

蘋果為了 SwiftUI,推出了 functionBuilder 來實現 DSL 形式的代碼;為了 SwiftUI,推出了許多讓它更漂亮的語法特性;為了 SwiftUI,不惜為語言引入更多的複雜度。

▐ 下限低,上限高

Swift 的最初的設計方向就導致了它是一門下限很低上限很高,入門容易精通難,使用容易設計難的語言。它一系列的語法糖和語法設計,包括類型推斷系統,都是讓它成為十分親民的語言,而它的一系列語法特性,讓它在設計 API、SDK實現的時候其複雜程度也不亞於其他語言。

Swift is a general-purpose, multi-paradigm, compiled programming language developed by Apple Inc. for iOS, iPadOS, macOS, watchOS, tvOS, and Linux.

---- Wikipedia

維基百科的後半部分可能有些侷限了,但是前半部分說明了它是一門多編程範式的語言,Swift 可以支持 面向對象編程(OOP),面向協議編程(OPP),聲明式編程(DP),函數式編程(FP),泛型編程(GP)。

Objective-C 已經發展了這麼多年,如此成熟,為什麼現在蘋果要開始拋開它?Objective-C 本來就是生於一個面向對象編程範式起飛的一年,與 C++ 一樣為了拓展 C 命令式編程範式而誕生的語言。當時 C 語言雖然也可以實現 OOP,但是語法設計成為了限制。在當代計算機編程語言研究演進下,出現了很多編程範式的新理論,如函數式編程,元編程等等,同樣 OC 可以通過它的方式來實現,但是語言的冗雜和 OOP 的設計已經不能更好的表達這些概念,就猶如純 C 來表達OOP 一樣。

蘋果推出 Swift 就是為了擺脫 OC 的束縛,讓它能更好的踐行現代的編程理論,所以才會誕生出 SwiftUI,才會有 Combine、map/filter/reduce 等這些庫和 API。類型推斷和元編程的理論也讓 Swift 在保留強類型的環境下還能保持如此簡潔優雅,可讀性強的代碼。而這些是 OC 無法做到的。嘗試使用 OC 對這些現代概念做表達的 SDK 都會顯得十分冗雜。

現在 Swift 語法已經不會再大變,有如此現代、安全、穩定、富有想象力的語言,有什麼理由不真香呢?

土壤已經肥沃

我們先通過下面的腦圖感受一下 Swift 更迭到 5.3 已經取得的成就。

image.png

現在 Swift 生態環境已經自成一派,有一套完整的工具鏈保證開發,有更獨立的標準庫讓它可以自由遷移,包管理讓豐富了它的 SDK,同時還具有 Native 語言的各種優勢。在這麼多年的發展中,它的能力已經觸及到了 AI、Server、Mobile Device、FaaS,強大的標準庫讓它甚至可以當腳本語言使用。

Swift 如今已經不再孤立無援,開源讓 Swift 變得生機勃勃,合理優雅的設計和開放的態度讓全球的開發者們都在不斷的完善它。

在 Swift 的大生態中,包管理工具是最值得一說的。一門語言它的能力,取決於它是否有強有力的 SDK,還有就是獲取他們的途徑。基礎的 Swift 的能力都由工具鏈和標準庫提供,而強有力的 SDK 最好的方式就是通過包管理工具快速獲取。Swift Package Manager 就是 Swift 的軍械庫。

▐ Swift Package Manager

看一下 Swift Package Manager(SPM) 的發展歷程,SPM 從 Swift 3.0 時就發佈,當時只支持 Git 遠端倉庫,支持支源碼發佈。WWDC 19,Xcode 引入了一個新的架構 XCFramework,一個旨在能打包多個平臺 framework 的文件結構。WWDC20 SPM 宣佈正式支持發佈二進制 framework。

WWDC20 SPM 走出的這一步標誌著功能的完善。為什麼這麼說,因為在 iOS 屆,解決了 Xcode 無包管理工具難題,讓眾多優秀的開源庫能被快速獲取的包管理工具 -- Cocoapods。在 SPM 出現之前,Cocoapods 的功能已經非常完善,打敗了當時另外的一款包管理工具 Carthage。

Cocoapods 作為基於 Xcode 開發的第三方包管理工具,通過修改 Xcode 的工程信息來實現處理各個包的依賴問題。它支持依賴的二進制分發、源代碼分發,基於 framework 良好的資源管理。現在許多公司的大型 App 也是用 Cocoapods 做模塊化組件分離,通過二進制依賴的方式來提高打包速度。

然而比較可惜的是它工作流是脫離 Xcode 的,Podfile 更新等操作都是在工程之外。語言使用的是 Ruby,雖然使用了一些操作使 Podfile 變成了 DSL,但是對於開發者而言是有一定門檻的,特別是需要編輯發佈 SDK 所使用的 podspec 時,對照文檔,無代碼提示的編寫讓寫正確配置文件都成了難事。Cocoapods 還不得不設計出 podspec lint 來幫組開發者確認這個事情。

對於 Swift PM 這個親兒子而言,就不存在這個問題,SPM 已經深入的集成到了 Xcode 中,所有的操作都可以利用 Xcode 完成。在編寫 Swift Package 時,Xcode 現在已經具備將 Package.swift 作為工程項目打開,並且現在工程模板中已經包含了 Swift Package。強大的 Xcode 自動補全讓編寫 Package.swift 不再是一件難事。如果脫離 Xcode,利用 swift-lsp 結合現在熱門的文本編輯器,如 VSCode 等都可以實現相應的功能。SPM 現在已經是獨立於 Xcode 的存在,可以為 Swift 提供強有力的支持。

SPM 在功能層面已經不遜於 Cocoapods,在 WWDC20 時,SPM 已經支持以二進制庫形式分發 Package,SPM 也可以管理包中的資源和本地化,基本的能力已經與 Cocoapods 差異不大,然而最關鍵的是,SPM 是純 Swift ,開源,還有蘋果官方支持的包管理工具。

▐ 新瓶釀酒酒更香

國外的不少 APP 已經遷移到了 Swift;三方開源庫如 AFNetworking 已經用 Swift 重寫為 Alamofire,Lottie 已經完全被 Swift 重寫替代。蘋果也推出了許多 Swift Only 的庫。蘋果也在利用 Swift 為 UIKit,GCD 等基礎庫不斷提供更具有表現力的 API。

Uber 完成了遷移,收穫了 Swift 極強的穩定性。Alamofire,SnapKit 用 Swift 重寫,獲得了更加具有表現力的 API,開發者更容易接受且喜愛。Reactive 系列的編程風格在 Swift 上大放異彩。

機會與展望

現在 Swift 發展了這麼多年,遍地開花,Objective-C 已經有在逐漸被廢棄的趨勢。現在很有可能都很難招到認真學習過 OC 的應屆生了。

Swift 在集團內部的發展,還有很多的工作要做,這其中充滿了挑戰。我們也在積極探索 Swift 在手淘的落地,取得了 Swift 5.1 能模塊在手淘中正確運行起來的階段性成就。但是比較遺憾的是還有很多模塊是無法讓 Swift 正確跑起來的,以現在的工具鏈來說甚至源碼依賴調試都無法做到。

但是這都是暫時的,現在時機已經成熟,Swift的語言特性,SPM,工具鏈,標準庫都已經足夠強大。未來,我們會盡快大力升級 Swift 的基建。讓 Swift 的花在集團內開起。先定個小目標,希望 Swift 能成為集團 iOS 客戶端開發的首選語言。

參考

SwiftUI 背後那些事兒

WWDC20 What's new in Swift

WWDC19 What's new in Swift

WWDC18 What's new in Swift

WWDC17 What's new in Swift

WWDC16 What's new in Swift

WWDC20 Swift packages: Resources and localization

WWDC20 What's new in SwiftUI

Swift 5 時代的機遇與挑戰到底在哪裡?

Swift Evolution

手淘客戶端團隊

負責手淘移動端的基礎PaaS及平臺技術。涉及移動網關、網絡加速、長連通道、圖片體驗等基礎技術,以及海量消息推送、浮層搭投全域觸達等平臺型技術,並對移動端系統進行前沿探索,打造了全站IPv6、iOS用戶態網絡棧、Android最小核、自適應線程調度等高性能技術和架構。

在這裡,你會面臨超級App在性能、體驗、安全等方面的極致追求;在這裡,你會站在業務和數據視角針對目標進行充分了解和深入優化;在這裡,你會與業界各領域大牛並肩作戰、快速成長。

我們期待有技術、有理想的你加入,與我們共享積極、透明、開放的團隊氛圍,伴隨著各種乾貨滿滿的分享培訓以及業務和技術挑戰,我們將一同在技術領域不斷攻堅、推陳出新,共同駛向屬於我們的星辰大海。

職位:iOS 開發、Android 開發、C++開發、Java 服務端開發、前端開發、數據工程師、算法工程師

感興趣的同學可將簡歷發送到:[email protected]

關注「淘系技術」微信公眾號,一個有溫度有內容的技術社區~

image.png

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top