[Day 2] SwiftUI 與 UiKit 之比較與選擇

前言 在 Day 1 時曾提到,這次要開發的 App,是讓使用者能直接輸入公路的里程數,並即時在地圖上定位。這次我選擇以 SwiftUI 來開發,除了想藉此機會嘗試這個框架外,更重要的是,我認為作為軟體工程師,理解各種技術的優勢與限制,並根據實際需求做出合適的選擇,是非常重要的能力。 技術本身只是工具,沒有絕對的對錯。關鍵在於能否根據專案目標、團隊狀況與未來維護等因素,做出最適合的技術選型,而不是單純因為新穎或流行。 而在 iOS 的原生開發中,主要有 UIKit 與 SwiftUI 兩個框架。SwiftUI 是蘋果在 WWDC 2019 發布的開發框架。以 2025 年的今天來看,它已不算最新技術,但相對於歷史悠久的 UIKit,仍是一個非常年輕的框架。 以下簡單對兩個框架做基本介紹。 SwiftUI 與 UIKit 簡介與比較 雖然本系列文章的重點並非深入比較這兩個框架,但這裡仍簡要說明其主要差異: 命令式語法 & 宣告式語法 命令式(Imperative)語法強調「如何做」:開發者需要明確描述每一步操作,手動管理 UI 狀態與流程。例如在 UIKit 中,必須指定元件的建立、佈局、狀態變更等細節。 宣告式(Declarative)語法則強調「要什麼」:開發者只需描述最終希望呈現的 UI 狀態,框架會自動處理狀態變化與畫面更新。例如 SwiftUI 中,直接描述畫面結構與資料綁定,讓 UI 隨資料自動更新。 我們用例子來說明可能會更清楚,以在畫面上放置一個按鈕,點擊後會增加數量紀錄的計數器為例,兩個框架的寫法相當不同: UIKit SwiftUI 可以看到程式碼的數量有明顯的差異。開發者只需將 count 變數與畫面元件綁定,當資料變動時,框架就會自動為我們處理 UI 更新。這不僅減少了手動操作 UI 的程式碼,也大幅降低了因狀態管理疏忽而出錯的風險。 除此之外,宣告式語法讓開發者的心力能更專注在「畫面應該長什麼樣子」,而不是「如何一步步把畫面變成想要的樣子」。對於我們的里程定位 App 來說,這代表當使用者輸入不同里程、或地圖狀態改變時,我們不必再手動更新標籤、按鈕或地圖標記的狀態,大幅提升了開發效率與程式碼的可維護性。 社群與資源 SwiftUI 看起來很棒對吧,而且每次修改完程式碼,右方會即時渲染。雖然後來 UIKit 也可以達到類似的效果,但我個人覺得還是 SwiftUI 比較方便。不過,SwiftUI 畢竟還年輕,當遇到較複雜或冷門的需求時,社群的資源與成熟的解決方案,仍不如歷史悠久的 UIKit 來得豐富,這點在查找資料時能明顯感受到差異。 性能與相容性 而 SwiftUI 許多新功能都需要較新版本的 iOS 才能使用。例如 NavigationStack(新版的導航結構)、Charts(繪製圖表)等元件必須 iOS 16 以上才支援。 因此若專案需支援較舊的 iOS 版本,SwiftUI 可能會受限,故需特別注意相容性問題。 ...

September 15, 2025 · 1 分鐘

[Day 1] 前言

與 iOS 開發的相遇 大家好,我是個從律師轉職的軟體工程師,踏入這個領域不知不覺也快兩年了。回想當初轉換跑道,一切從自學 Python 開始,接著摸索資料庫、API 等後端技術。後來有幸進入 AppWorks School (現已更名為 AiWorks) 接受 iOS App 開發訓練,最終進入金融業的 IT 部門。 進入公司後,我的工作日常相當「精彩」,除了本行的 iOS 專案開發與維護,還得兼顧後端維運、和 SQL 打交道,甚至管理 Splunk、Kong APIM 這些系統。雖然實際能投入在 iOS 開發的時間不如預期,但我對這塊領域的熱情從未減少。親手打造出一個能看、能用、能互動的應用程式,那種從無到有的創造感與成就感,是其他工作難以比擬的。也因此,剛進公司時,對於無法專注在 iOS 開發上,心裡難免有些失落。但現在回頭看,我相信廣泛接觸不同技術對一個軟體開發者來說絕對是不虧的事情。然而,心中那份對 iOS、特別是 SwiftUI 的渴望,依然強烈。 目前公司的專案仍以 Objective-C 與 UIKit 為主,雖然我曾用 SwiftUI 開發並上架過個人 App,但總覺得學得不夠扎實。這次鐵人賽,對我來說正是一個完美的機會,能強迫自己更多了解 SwiftUI 的世界,將那些零散的知識串連起來。 初入 DevOps 世界 在公司任職期間,我有幸參與了 Azure DevOps 的導入過程。坦白說,起初它對我而言,就只是個「新來的工具」:用 Wiki 寫文件、開 Work Items 追蹤任務、等 Pipeline 編譯出 .ipa 檔,然後透過 Pull Request (PR) 進行程式碼審查。每個環節都得遵循特定流程,像是 Pipeline 還需要主管審核才能部署,有時覺得有些繁瑣。 但隨著時間推移,這些經驗讓我逐漸體會到,DevOps 不僅僅是工具的堆砌,它更是一種文化,一種讓開發、測試與部署流程更順暢、更可靠的思維模式。當我看到一個小小的修改,能自動觸發測試、打包、甚至部署到測試環境,我才真正理解自動化所帶來的安心感。 即使現在是一人開發的個人專案,我也相信導入良好的 DevOps 實踐也是一個不錯的嘗試: 版本控制: 使用 Azure Repos 搭配 Git-flow 策略,讓每一次的程式碼異動都有所依循。 自動化測試: 設定 Pipeline 自動執行單元測試,確保程式碼品質。 持續整合: 每次提交程式碼後自動編譯並檢查。 持續部署: 自動將測試通過的版本部署到 App Store Connect。 這次的系列文章,我將結合 SwiftUI 開發與 DevOps 實踐,從建立基礎專案開始,一步步實現自動化的開發流程。 ...

September 14, 2025 · 1 分鐘

canOpenURL 與 openURL 的那些事

之前因為一直沒有機會去處理到不同 App 之間跳轉的問題,對這塊的東西一直不太熟悉。最近因為遇到 App 不能成功開啟其他 App 的問題,才有機會了解一下。 不能開啟的原因是 App 使用很久以前的 API: 可以看到在 iOS 10 以後就被蘋果棄用了,然而蘋果棄用通常並不表示馬上不能用,所以這支 API 還活了很久一段時間,直到 iOS 18 蘋果才真正不給用。這支 API 已經被 open(_:options:completionHandler:) 取代(Objective-C 為 openURL:options:completionHandler:): 雖然這個問題解決了,但我想藉此機會多了解一下跳轉這個機制。 要實現 App 能夠跳轉,例如 20250829_B 這個 App 要能夠讓被其他 App 開啟,就必須要去 target 設定裡的 Info 分頁,在 URL Type 裡面替自己定義 URL Schemes,這裡我們定義為 AppB。 接著,我們在另一個 App A 裡建立一個點擊會實現跳轉 AppB 的按鈕 程式碼如下: @IBAction func jumpToB(_ sender: Any) { let scheme = "AppB://" guard let url = URL(string: scheme) else { return } UIApplication.shared.open(url, options: [:]) { success in } } 我們僅實作 open(_:options:completionHandler:),而不實作 canOpenURL(_:) 這支很常被使用的 API。 ...

August 29, 2025 · 1 分鐘

API 雜談

前言 本篇算是整理下目前自己對 API 的理解,算是雜談性質,就記錄一下吧。 什麼是 API (Application Program Interface) ? 從文義解釋開始 從文義解釋來看,API 的基本定義是:軟體之間溝通的介面,允許不同系統有規範地交換資料。API 規範了如何向服務提出請求、需要的資料格式,以及回傳結果的形式。 然而文義解釋總是過於抽象,我們還是舉例來說明會比較清楚。在介紹何謂 API 時,最常聽到,會用餐廳點餐來比喻,我這裡也不免俗地用這個方式來說明。 餐廳的例子 Image Source Credit: Celeste Layne - Medium.com 你是餐廳的顧客,菜單代表「服務可以提供那些資料、功能」。當你向服務生點餐(發送請求),服務生將你的請求帶給廚房(資源所在,也就是後端系統)。廚房根據菜單和你的選擇(麵要加大不要辣)的選擇製作食物(處理請求)。最後,服務生把餐點(回應)端給你。 在這個比喻中,服務生就像 API,客戶端(顧客)不直接與後端(資料、邏輯、資源)打交道,而是透過 API 這個介面來溝通下單和取得結果,省去彼此理解內部細節的麻煩。 但是,工具的目的是為了解決問題,重要的不是工具本身,而是背後要解決的那個問題。因此我們要進一步思考的是,如果沒有 API,會如何? 軟體之間就必須「直接訪問」彼此的資料或功能,彼此須了解對方的內部細節,如同點菜時顧客沒有按照制式的菜單點餐,廚房根本不知道怎麼出菜,最後本人必須進廚房了解每一道手續,如此一來餐廳根本無法運作。但若真的讓顧客直接進餐廳,如此,就會缺乏安全隔離,外部程式可以隨意取得資料,使系統變得脆弱,就像顧客可能將病原體帶入廚房,污染食材。同時,維護上若有需要調整,將會修改困難,比方說內部實作細節更改,取用者要如何取得資料,必須重新理解取用過程。 舉例來說,如果沒有 API,你開發一個 App,需要取得 google 地圖的資料、處理金流等功能時,你得直接接觸這些系統的底層,理解提供服務者的內部結構才能夠拿到你想要的東西。 訂購人的困境 OK,現在每一家餐廳都有自己的菜單與訂購單,解決了廚房的溝通問題。這解決了單一廚房點餐的問題,基本上只要看得懂上面菜單的文字,就可以知道這張單要出甚麼內容。我們有了 API 了! 但若場景變成:要對多個餐廳要同時下單,你是訂便當股長,就會遇到要對應不同便當店,要看懂每家的菜單格式,還要想辦法看懂各位同事自由格式的信件內容,也就是你要適應不同格式,結果就是增加了溝通成本。 例如上圖,每間餐廳的菜單風格迥異。 開發人員的困境 回到開發場景。來做個系統吧,資訊人員一定會幫我們解決這個問題,降低便當股長的離職率。但資訊人員遇到了問題,那就是他要去串接的每個店家,他的訂購單格式都不一樣,此時面對了一些抉擇: 鍛鍊資訊人員,所有店家都客製作下去,但這可能會提高資訊人員離職率。 訓練資訊人員的溝通能力,配合專案經理,以及外部合作商,談訂一個共同的規格。 很遺憾的,上面那兩個選項,偉大的老闆選了項目 1,為了不影響其他合作商,所以決定讓自己的工程師處理。 如果每個合作對象(例如不同餐廳)都用自己的格式來傳遞資料,資訊人員(工程師)就必須針對每一種格式,開發不同的「解析」方法。舉例來說: 有的店家用 Word 檔案下訂單,有的用 Excel,有的用 PDF,有的直接寄圖片,有的用網頁表單。工程師就要寫很多不同的程式,來讀取和理解這些不同的檔案格式。 如果店家改變了檔案格式(例如 Word 從 2003 版換成 2007 版),工程師的程式就可能失效,要重新修改。 有的 Excel 檔案可能被植入病毒,還要擔心安全問題。 如果是圖片,還要用影像辨識技術來「看懂」圖片內容,萬一圖片字體換了,辨識又會出錯。 ...

August 11, 2025 · 2 分鐘

Kong OIDC Plugin:Token 驗證筆記

前言 當你的 API 以 OpenID Connect 協定實作 authentication(認證)時,就會使用到 Kong OIDC(OpenID Connect) plugin。本篇要關注的是,當利用 OpenID Connect 協定,讓 Kong 在認證階段自動與 IdP(例如 ADFS)整合,獲取並驗證 JWT Token,保證只有合法使用者能夠存取上游服務的這個過程。 驗證流程 當 Kong 收到來自 consumer 的請求後,會進行以下流程: Issuer Discovery Kong 透過 OIDC plugin 中的 issuer 參數,從 .well-known/openid-configuration URL,自動抓取 IdP 的 Metadata。Metadata 包含 jwks_uri(JSON Web Key Set)endpoint,用於後續公鑰獲取。 若在 plugin 的 extra_jwks_uris 有設定放置公鑰的 URL,Kong 會先依序對每個 extra_jwks_uris URL 嘗試下載 JWKS。若所有 extra_jwks_uris 都無法成功(連線失敗或無對應公鑰),再從 .well-known/openid-configuration 中的 jwks_uri 嘗試;若未設定 extra_jwks_uris,則會直接使用 .well-known Metadata 提供的 jwks_uri。 Token 取得: Kong 會對 ADFS 發起請求並獲取並 JWT Token。 ...

August 11, 2025 · 1 分鐘