詳解 WWDC 20 SwiftUI 的重大改變及核心優點

導讀

6月23日凌晨 1 點,蘋果 WWDC20 開發者大會在線上以主題演講的方式,在 Apple Park 進行直播。 git

23-26日,蘋果公開了 100 多個面向開發者的視頻,內容涵蓋Swift / SwiftUI 、App Clips、Widgets、Privacy & Security 等等方面。程序員

對於開發者和程序員來講,咱們有哪些新發現和新思考?github

淘系技術客戶端團隊,將給你們帶來一系列關於新系統背後的啓發,歡迎交流討論。編程

本篇內容來自於阿里巴巴淘系技術部,淘寶客戶端iOS架構組,高級開發工程師傾寒。swift

前言

SwiftUI 是蘋果公司於 2019 年推出的 Apple Platform 的新一代聲明式佈局引擎,筆者於去年第一時間升級 Beta 嚐鮮全家庭,並在短期內迅速落地了基於 SwiftUI 的內部 APP, 也分享了幾篇關於 SwiftUI 的文章, 但 SwiftUI 1.0 基本沒有任何公司敢用在正式上線的主 APP 上,API 在 Beta 版本之間各類廢棄,UI 樣式常常不兼容,大列表性能差,彼時都標識着 SwiftUI 還稱爲一個 Toy Framewrok.安全

隨着 WWDC 20 相關新特性和介紹視頻的釋出,都明確的宣告着 SwiftUI 元年已經到了,SwiftUI 已經成長爲新時代的佈局引擎。網絡

如下從幾個方面分享關於 SwiftUI 的重大改變及核心優點。
數據結構

PS: 須要讀者對 Swift 及 SwiftUI 1.0 有必定熟悉。閉包

SwiftUI Apps

蘋果在最近幾年的動做中一直在搞 Apple Platform 統一的事情,從最近幾年的 iPad 多任務 多窗口,到 Mac Catalyst 再到今年更進一步直接推出了 Apple silicon 芯片更是從硬件上作到了真正統一(話外音: 大家在軟件上玩的那些跨平臺的都是小玩意,硬件纔是王道)。
還提供了 Rosetta2 Universal2 幫助開發者基本無成本的遷移到新平臺上。可是做爲軟件工程師仍是要更多的關注軟件生態的變化。首先了解下建立 APP 時的變化架構

能夠看到建立新工程時有了一套全新的模板基於 SwiftUI App Lifecycle 的跨平臺項目。
代碼也從本來的基於 UI/NS HostViewController 變成了基於 APP 的聲明式描述,下面是代碼的先後對比

  • Before

    屏幕快照 2020-07-15 上午11.36.38.png

  • After

屏幕快照 2020-07-15 上午11.36.47.png

其中@main 是Swift 5.1 新增的 Attribute 標記了應用程序的入口點,更多請參看SE-0281-main-attribute.md

乍看好像只有代碼精簡了很多,不少人會認爲這個簡潔程度還不如Flutter 的 main() => runApp(MyApp());.

但最重要的變化是這是第一次跨平臺代碼,徹底無需引入任何 UIKit APPKit WatckKit 等相關Framewok, 便可直接運行在不一樣平臺上。這意味着咱們後續在UI佈局系統上能夠逐漸擺脫對傳統命令式 UI 編程的依賴。達到真正的平臺無關。

SwiftUI 將整個原有的平臺差別部分抽象爲 App 和 Scene,對於一個 mac/iOS/iPad/watch/tv/..應用,來講 App 表明了整個應用,Scene 表明了與 Window 相關的多窗口,有些設備只有一個 Scene 有些則有多個,雖然不一樣的 OS 確實存在差別,可是在語義層面達到了一致。

其次一個沒有歷史包袱的 APP,也能夠完整的從 Swift APP lifecycle 風格式的模板開始,無需再和傳統的 UIKit/APPKit 等混合。這也意味着能夠達到 APP 徹底 Declared and State-Driven


Viusal Editing

Preview

在傳統的利用 DSL 可視編程框架或者平臺,諸如 Web Flutter 等技術,都是開發者編寫好對應的代碼,運行在對應的平臺或者調試工具上。  SwiftUI 做爲蘋果最重要的軟件層戰略框架,更是和 Xcode 深度結合,在運行以前就能夠完整的預覽你所編寫的界面。

強大的 Preview 可讓你既能夠從編寫 DSL 到當即預覽效果,也可從預覽的 Canvas 畫布中直接修改效果在代碼編輯器中生成代碼,這對於平常開發的效率有很是大的提升,尤爲是在 UI 微調時,效果尤其突出。
Xcode12 能夠在 Canvas 上同時預覽多個不一樣設備環境的界面,也能夠直接投射到真實的設備上來預覽。

對於平常開發來講,編寫一個UI界面一般依賴外部的網絡/磁盤/其餘數據,才能正常的構建,這也形成了UI開發雖然是開發中較爲簡單的一步,但同時也是最耗時的一步,有了預覽功能,能夠把不少繁瑣的工做前置解決掉,對於研發效率會有很是大的提升。

Xcode Library

在編寫真實項目中,一個公司的 APP UI 包含成百上千種風格的 View 組件,對於 UI 組件豐富的產品,若是一個新需求能夠由現有的組件組合,那麼需求交付的時間也會大大縮短。
可是對於一個大型的開發團隊而言,一個開發同窗是很難知道公司內到底有多少種組件庫,並且即使知道有某種組件庫,開發同窗初期看到的也是代碼,通常須要書寫必定的 Demo 才能夠用眼睛感知到這個組件究竟是否是我想要的。
在 Xcode 12 中提供了更強大的工具,一個自定義組件,只須要遵照一個 LiberyContentProvider 協議就可被Xcode識別,能夠像系統控件同樣直接從 Xcode 裏面識別並預覽。對於一個大型團隊來講,此功能能夠大大提升找尋組件和查看組件樣式的效率。

屏幕快照 2020-07-15 上午11.38.46.png

DSL

隨着 Swift5.3 和 SwiftUI2.0 的推出,SwiftUI 在 DSL 上也更富有表現力, Swift 支持了多重尾閉包語法和在 ViewBuilde 裏面支持 Switch Case 語句。

Multiple Trailing Closures

雖然社區對多重尾閉包的討論上一直存在爭議問題,但最終 Swift5.3 仍是接受並實現了,在普通命令式編程的地方使用會有必定的困惑性,可是在 SwiftUI 中
DSL 也更有聲明式的味道。

屏幕快照 2020-07-15 上午11.47.57.png

Switch Case Support

在 SwiftUI 的 ViewBuilder DSL體系中也支持了 Switch case 語法。

屏幕快照 2020-07-15 上午11.48.38.png

Data Flow

在使用傳統命令式編程編寫 UI 代碼時,開發者須要手動處理 UIView 和 數據之間的依賴關係,每當一個 UIView 使用了外部的數據源,就代表了 UIView 對外部的數據產生了依賴,當一個數據產生變化時,若是意外的沒有同步UIView的狀態,那麼 Bug 就產生了。

處理簡單的依賴關係是可控的,可是在真實項目中,視圖之間的依賴關係是很是複雜的,假設一個視圖只有 4 種狀態,組合起來就有 16 種,再加上時序的不一樣,狀況就更加複雜。

人腦處理狀態的複雜度是有限的,狀態的複雜度一旦超過人腦的複雜度,就會產生大量的 Bug,而且修掉了這個產生了新的Bug。


那麼 SwiftUI 是如何解決這個問題的?
SwiftUI 的框架提供了幾個核心概念:

  1. 統一的 body 屬性,SwiftUI 自動從當前 App 狀態集自動生成基於當前狀態的快照 View。
  2. 統一的數據流動原語。

關於 SwiftUI 中的 Data Flow 是如何消除視圖和狀態不一致的,請參考去年撰寫的文檔 系列文章深度解讀SwiftUI 背後那些事兒

今年 SwiftUI 2.0 新增的 StateObject 數據流原語讓 SwiftUI 在重複建立 View 時避免重複建立 ObservedObject 從而提升 View 重建的性能。
SceneStorage 和 APPStorgae 讓一些可持久化的數據變得更加簡單且具備語義化。

New Controls

前面提到的,新增的 DSL 語法 SwiftUI App Lifecycle,以及 Xcode Library Preview 其實本質上都是對去年 SwiftUI 1.0 錦上添花的新擴展
真正重要的是今年新增的各種新控件,其中經過導出來自 Xcode11.5 和 Xcode12.0 beta 版本的 Swift 聲明文件,能夠觀察到整個聲明文件從原來的 10769 行增長到 20564行。
新增了約 87 個 struct 16 個 protocol。 有了這些豐富的組件才能夠更好的構建咱們的 APP 。

大列表組件

在任何一款 APP 中都會存在相似大列表組件,如淘寶 APP 裏面的某家店鋪裏面商品列表流,首頁的信息流,都是具備超長內容的列表頁數據。 對於長列表頁來講,過長的 UI 頁面會致使過多的內存佔用,在用戶的設備中,內存是最爲重要的指標,對於目前國內的 APP 市場,低端手機仍然佔據大量的市場,對於這些設備來講,一旦內存超標,APP 就很容易 OOM,這會致使用戶體驗很是差,在現有競爭關係激烈的市場環境下,體驗差意味着會失去用戶。

對於傳統的命令式編程來講,咱們能夠主動控制 UITableViewCell 的重用,自建緩衝池等一系列手段去優化咱們的 APP 內存佔用,可是對於 SwiftUI 1.0 來講,系統提供的控件並無有效的辦法去讓咱們控制頁面的渲染,對於大列表頁面就容易出現內存佔用太高的問題。
SwiftUI 2.0 推出了 LazyHStack 和 lazyVStack 加上 List 渲染模式默認就是 Lazy 的直接解決了最大的性能問題,

筆者以去年使用 SwiftUI 編寫的 Emas App 爲例,當列表頁(並沒有大圖)加載到 500個時, APP 使用內存已經達到了將近 360MB 。而只須要切換到 Xcode12 API 調整爲到 LazyVStack 內存佔用直接下降 300MB

Widget and Clips

蘋果與 WWDC 20 推出的 WidgetKit 支持的 API 是 SwiftUI Only,雖然已經能夠混合部分UIkit 裏面的View,但相信沒有歷史包袱 最低支持版本爲 iOS14 的 Widget 沒有人會選擇笨重的命令式 API。
同理 Clips 也同樣。 這裏由於篇幅緣由就不作展開,後續會有專門的文章分析相關技術。

Swift & SwiftUI 的機會在哪裏?

筆者曾經在公司推進集團升級了基建,支持了 Swift 開發環境也在淘寶落地了一些場景,可是集團內一直有一些質疑的聲音, 引入 Swift 到底有什麼用?
SwiftUI 又是 N 年後才能夠用上的小玩意,Objective-C 不夠用嗎?如今筆者能夠回答這些質疑的聲音, Swift 將來的機會在 效率體驗

效率

從研發效率上來講, Swift 對比 Objective-C 的精簡程度不言而喻,筆者在淘寶 APP 上線的模塊代碼量降低了 40 %
但更進一步,若是編寫 UI 界面從 UIKit 轉向了 SwiftUI 代碼量直接少了不止一倍。 更少的代碼意味着更快的交付,在目前競爭激烈的市場會有更多的試錯場景。

關於使用 UIKit 編寫代碼轉向 SwiftUI 的代碼量對比,讀者能夠參考開源 APP MovieSwiftUI 直觀瞭解

體驗

讀者可能比較困惑對於切換語言和框架,對體驗看上去沒有任何幫助,但事實真是這樣嗎?
首先引入 Swift 後,因爲 Swift 語言設計之初便對安全性列爲最重要的目標,Swift的引入會讓代碼儘量的減小未定義的行爲,減小 Crash 意味着APP的穩定性提升,體驗天然更佳。

其次雖然 Swift 一樣的語言出於對安全性考慮編譯處理的指令會比 Objective-C 更多,可是若是UI部分都用 SwiftUI 來寫呢?
更少的代碼意味者更小的包大小,目前國內巨頭 APP iOS 端 APP 包大小都朝着 200 MB 奔去,若是能減小更多的代碼對包大小也能夠在 200MB 的限制下承載更多而業務。對用戶的體驗也有較大的提高。

更進一步因爲 Swift 選擇使用值類型構建整個APP,值類型的有點在於更扁平化的內聯數據結構去分配內存,而不是使用更多間接指針引用,減小了大量沒必要要的堆內存消耗,意味着總體內存使用量的下降
對整個 APP 的穩定性也有較大的提升。

蘋果的選擇

Swift 作爲蘋果的戰略語言已經發展的愈來愈壯大,自 2019 年 Swift ABI 穩定後,蘋果在 Swift 的投入愈來愈大。咱們能夠進入 /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/swift , /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks , https://github.com/applehttps://github.com/swift-server 看到, 自 iOS 13 以來 蘋果新增了約 10+ Pure Swift Library , 10+ Open Source Swift Library, 以及針對 144 個公開 Framework,根據 Swift Style 從新設計了 57 個 Framework 的API。
從如下數據

  1. 從 WWDC17 後 蘋果已經再也不使用 Objective-C 作 Sample Code 演示
  2. https://developer.apple.com/再也不更新  Objective-C 相關的文檔
  3. WidgetKit 是 SwiftUI only。
  4. App Clips 10M的包大小, SwiftUI 是最合適的框架
  5. 開源社區逐步放棄 Objecive-C 如 Lottie。

能夠判斷,Swift 是將來 Apple 平臺的惟一選擇,越是有包袱的大廠 APP,從如今還不盡早儲備,在將來越會步履維艱。

咱們須要作些什麼?

Swift

咱們已經作了什麼
  1. 一套支持 Swift 二進制的研發環境
  2. 300+ 支持了混編的淘系 SDK。
  3. 手淘落地了 6 個模塊。
  4. 集團新增了約 20個 支持 Swift 的APP。
  5. 10 多場技術培訓。
  6. 169+ 語雀知識沉澱。
  7. 300+ 工程師的集團 Swift 官方組織。
  8. 2 個 技術創新產品

通過去年橫向組織你們共同的努力,咱們已經已經支持了橫向大基建。包括研發環境,工具支撐,沉澱了大量的文檔,還有相關的技術課程。

要朝什麼方向去努力

目前集團對於 Swift 的呼聲愈來愈高,咱們大量的工程師但願的去使用 Swift 。目前首先要作的事情是依託 Swift 和 SPM 提高咱們的開發體驗,升級咱們的中間件,使業務能夠大量的用起來 Swift ,提升咱們的研發效率和代碼質量。

  1. 升級基於 SPM 的新的包管理體系
  2. 升級老舊基礎庫,打磨新一代基建。
  3. 引入新的 Swift 特有庫 賦能業務。

SwiftUI

雖然前文提到了 SwiftUI 的衆多優勢,包括研發效率,體驗的提升,可是在國內的環境中 SwiftUI 也有它致命的弊端

  1. iOS 14 纔可放心的使用。
  2. 只支持 Apple Platform,這和國內的要支持 Mobile Platform 從理念上衝突。

大型 APP 要解決的是如何部署到低版本操做系統上和安卓平臺上,畢竟不少公司還在支持 iOS 9 對於升級到最低支持 iOS 14 好像還須要一個世紀那麼漫長,並且國內的設備佔比大頭仍是以 Android 巨多 。
雖然能夠看到 Swift 語言也在逐漸支持 Android 平臺,可是也看到蘋果對於安卓平臺的 SwiftUI 並無太大興趣。

從體驗上 Flutter 遠不如 SwiftUI 這種親兒子效果好, 但對於國內跨端慾望旺盛的市場來講 SwiftUI 仍是比不過 Flutter, 不過既然 SwiftUI DSL 層已經基本固定,那麼也有可能投入人力直接在低版本操做系統上實現一套自建的 SwiftUI 引擎,或者將 SwiftUI 引擎移植到安卓平臺,好比對接 Flutter 或者直接對接 Android Native。
比起 Flutter 引入雙端帶來的包大小增量和體驗不一致的狀況, SwiftUI 保留 iOS 平臺體驗,只侵入一端的選擇顯然要更好一點。

招人啦!

歡迎投遞簡歷~ 手淘客戶端架構組,負責淘寶客戶端的基礎框架包括組件化容器、啓動器、路由、UI框架等,負責高可用包括Crash、卡頓、內存、耗電等監控,負責全局性能、體驗優化,負責重點技術包括存儲、日誌、修復等,負責系統新特性、新技術、新設備探索,在這裏你會面臨海量用戶、大規模業務、雙十一大促帶來的巨大技術挑戰,你能與資深大牛並肩做戰,深刻系統內核研究解決複雜問題,迅速成長爲業界優秀工程師!
簡歷投遞:qinghan.jy@alibaba-inc.com

參考

  1. SwiftUI 背後那些事兒
  2. MovieSwiftUI
  3. SE-0281-main-attribute.md
  4. Add custom views and modifiers to the Xcode Library
  5. Structure your app for SwiftUI previews
  6. Introduction to SwiftUI
  7. What's new in SwiftUI
  8. App essentials in SwiftUI
  9. Visually edit SwiftUI views
  10. Stacks, Grids, and Outlines in SwiftUI
  11. Build document-based apps in SwiftUI
  12. Data Essentials in SwiftUI
  13. Build a SwiftUI view in Swift Playground
  14. Build SwiftUI apps for tvOS
  15. Build SwiftUI views for widgets
  16. Build complications in SwiftUI
  17. What's new in Swift
  18. Swift packages: Resources and localization
  19. Distribute binary frameworks as Swift packages
  20. Explore logging in Swift
  21. Create Swift Playgrounds content for iPad and Mac
  22. Embrace Swift type inference
  23. Explore numerical computing in Swift
  24. Unsafe Swift
  25. Safely manage pointers in Swift
  26. Explore numerical computing in Swift [
  27. Explore Packages and Projects with Xcode Playgrounds
  28. Use Swift on AWS Lambda with Xcode
相關文章
相關標籤/搜索