在 2019 年的 WWDC 大會上,蘋果推出了一個全新的 SwiftUI 框架,這是一個現代化的 UI 界面編碼結構,它是基於 Swift從頭開始構建的。新框架使用聲明性範例,讓開發者用更少的代碼編寫相同的 UI。
SwiftUI 的願景是降低開發 iOS 門檻,吸引更多開發者、豐富 iOS 的業態。並且 SwiftUI 可以「實現一次編碼,可適應五端 Apple 產品平台」, 包括watchOS、tvOS、macOS 等,以此統一蘋果平台的 UI 框架。
蘋果傳遞出來的消息就像是說:「SwiftUI 是一個了不起的用戶界面框架,而且 100% 絕對會成為蘋果平台上應用開發的未來。」
這些年,也有一些用 SwiftUI 重寫 UIKit 應用程序的案例,去年奈飛新版 iOS App 的登錄界面也完全由 SwiftUI 重構。
本文的作者 chsxf,是一家獨立遊戲工作室的首席開發,也是 15 年的蘋果用戶,他想嘗試將 SwiftUI 放到自己的項目中,但是最終失敗了。他發表了一篇博客,總結了嘗試並放棄 SwiftUI 的過程,這篇文章在 Hacker News 上引發了開發者們的大量討論:
「恕我直言,SwiftUI 是一個很好的機會,但蘋果公司對它投資不足。這是一項很好的技術,響應式方法非常適合許多典型的基於視圖的需求,但對如何處理邊緣情況,文檔中非常缺乏相關的說明。」
「這是個好主意,但 SwiftUI 的主要問題是完全不成熟。」「它具有複雜的行為,不適用於需要大容量或複雜 UI 的 App。」
「而且 SwiftUI 改進太慢了。」
..........
最近,我手頭正好有個「The Untitled Project」(名字還沒想好)項目需要完成。考慮到配套創作工具 CiderKit 在發展成熟的過程中也變得愈發複雜,再加上創建各種窗口和 UI 元素的實際需求,我決定嘗試用用 SwiftUI。這是個寶貴的機會,能讓我認真體驗一把 SwiftUI 並探索其內部工作原理。
起初項目工作良好,我對 SwiftUI 的表現可以說非常滿意,我甚至創建了自己的修改器,以便更輕鬆地顯示警報消息。但美好的甜蜜期很快過去,接下來我就要說道說道 SwiftUI 的那些「壞毛病」了。
接下來,我開始了 SwiftUI 探索之旅的第二站——為地圖編輯器創建實時檢查器。跟其他創作工具一樣,這款檢查器的功能就是選定一個對象,並把可檢查的對應屬性顯示在一個臨時的用戶界面元素當中。過程當中,Swift 協議和它處理泛型的方式也給我帶來了不少麻煩,但這裡我們就不過多展開了。
我還遇到了其他問題,因為 SwiftUI 高度依賴於 View 協議的實現結構,但 View 協議又有關聯的類型,所以只能把它當成約束來用。好在配合 some 關鍵字和 opaque 類型等設計,我最終還是為可選對象找到了一種實現方法,讓每個對象都能提供自身特定的 UI 元素。
之所以下決心選擇 SwiftUI,就是因為初步測試時效果不錯。如上圖所示,地圖編輯器位於左側,檢查器位於右側。起初,我測試了一個 UI 元素,那是個用於開燈和關燈的勾選框。它運行良好,所以我根本想象不到後續會出什麼大亂子。
但在開始實現更複雜的檢查器視圖時,特別是涉及帶有 / 不帶步進器或顏色選擇器的多個文本字段時,整個運行速度開始劇烈下降。SpriteKit 視圖一般都能以每秒 60 幀的完美速率呈現(只要用的不是英特爾孱弱的 iGPU)。但每當 SwiftUI 更新檢查器視圖時(這種更新可能出現在移動過程中,甚至是在輸入文本字段的時候),渲染速率都會下降到每秒 10 到 15 幀,而且相當不穩定。這顯然讓人無法容忍。
我認真做了一番分析,並發現了幾個問題。首先,由可選對象提供的視圖在每次重繪時都是在完全重新創建。我雖然通過緩存稍稍提升了性能表現,但實際體驗仍然非常糟糕。事實證明,SwiftUI 檢查器視圖就是沒法提供合理的重繪速度。我在網上查找了解決方案,最後編寫了一個延遲版本的 ObservableObject,由它來強制每秒只發布一次更改(參見以下代碼)。
隨着重繪頻率的降低,終於能比較順暢地操作地圖上的對象了,每秒的幀率浮動一般就只有個位數。但這會導致檢查器中的值出現延遲,因此在地圖編輯器的交互過程中(比如使用移動工具時)結果不準確,所以效果還是稱不上完美。
但我覺得這可能只是個獨立問題,並不能因此把 SwiftUI 一棒子打死。所以,我打算繼續探索。
在實現了第一個檢查器之後,我開始研究另一個主題:Sprite 資產編輯器。利用這款工具,我可以用多個 sprite 拼接成複雜的資產,再最終為它們製作動畫。它的顯示效果就是主窗口中的一張表,出於學習的目的,我當然還是想繼續用 SwiftUI 嘍。畢竟初次嘗試肯定會有種種問題,應該再給它一次機會。
如大家所見,這是個複雜的窗口,包含多種不同上下文(上方的「Sprite 資產數據庫」列表,左側的特定「Sprite 資產數據庫」內容,以及其他與選定 Sprite 資產對應的編輯器元素)。我需要為每個上下文創建一個視圖,這些視圖同時又是其他視圖的「子視圖」,然後把需要的數據傳遞給特定視圖。
但上圖展示的效果其實是在 AppKit 中完成的,因為我在 SwiftUI 一直實現不了預期的功能。大家應該注意到了,中間的 SpriteKit 視圖上有三個按鈕(分別是 +、200% 和 -)。這些按鈕只跟管理 SpriteKit 視圖縮放的 @State 相關聯。儘管幾乎不涉及任何其他數據,在界面更新前單擊這些按鈕,也會產生將近一秒鐘的巨大延遲。我剛開始以為是因為地圖編輯器的 SpriteKit 主視圖仍在後台渲染。所以我嘗試在工作表顯示出來後禁用渲染,但結果沒有任何改變。
變更從一種環境傳播至另一環境時,我也遇到了類似的延遲問題。這可以說是壓死駱駝的最後一根稻草了,我決定放棄 SwiftUI,繼續用 AppKit。
其實沒能在項目中用到 SwiftUI,會讓我感覺有點遺憾。我仍然覺得它是一項很棒的技術,只是可能不適合我的這個特定用例。但我真的不確定是不是自己的用法有問題。我打算在 Nihongo no Kana 的更新版本中再用用 SwiftUI,畢竟那款 iOS/iPadOS 應用的重繪頻率低得多,所以應該不會有太大問題。
也許 SwiftUI 還沒做好全面替代 AppKit 的準備。The Untitled Project 的 CiderKit 創作工具並不是作為 Catalyst 應用構建的,也不依賴於 UIKit。但繼續使用 AppKit 的最大優點,就是沒有任何延遲而且一切功能完全符合預期。當然,整個構建過程更繁瑣,而且自動布局功能也不怎麼好用。但我至少可以更好地控制應用程序的行為,而且根據需求隨意調整各種元素。
總之,經歷了這麼一番波折,我還是很慶幸自己果斷放棄了 SwiftUI。這可能是我在這個項目上做過的最明智的選擇。
參考鏈接:
https://chsxf.dev/2022/08/28/5-tup-why-i-quit-using-swiftui.html
https://news.ycombinator.com/itemid=32630389
https://xie.infoq.cn/article/28af907f31baa7e7283a31ed4
英偉達回應「對中國斷供部分高端 GPU」;月薪 3.6 萬工程師日均寫 7 行代碼被開;12 年黑進 40 多家金融機構老闆賺百萬獲刑 |Q 資訊
在阿里達摩院搞了四年數據庫,我來聊聊實際情況 | 卓越技術團隊訪談錄
30 年 IT 老兵談數字化:這就不是個技術活
資深 Web 開發的經驗之談:為什麼你開發的網頁不應該大於 14KB?
前阿里 P10 、浙江大學博導東白老師在極客時間出個專欄,叫《郭東白的架構課》,非常火爆,已經有超過 2w 人學習了。
這個專欄共 67 講,約 35w 字,內容包括「架構師的六大生存法則、架構師的價值創造、程序員職業成長、程序員思考力提升」四個模塊,適合架構師學習,更適合未來想成為架構師的朋友學習。
專欄過兩天就漲價到 ¥199 了,極客時間新用戶限時 ¥59,推薦入手!
👇長按掃碼,可免費試讀👇