[譯]沒有 Interface Builder 的生活

rydenryden發表於2018-03-26

沒有 Interface Builder 的生活

[譯]沒有 Interface Builder 的生活

在過去的幾個月,在 Zeplin 的 macOS 版本 app 中,我們開始在開發一些新的功能時,不使用 Interface Builder 或者 Storyboards。

在 iOS/macOS 社群,這是一個很具有爭議性的話題,並且作為一個之前極其依賴 Interface Builder 的團隊,我們想用一些真實的案例,來分享一下我們為什麼做了這個轉換。即便這篇文章是從 macOS 方面出發的,但其中我提到的任何東西都可以被應用到 iOS 上。

為什麼?

在用了兩年的 Objective-C 後, Zeplin 在 2015 年末,第一次用 Swift 來編寫其中一個模組。從那以後,我們一直使用 Swfit 開發新的功能並且逐漸地遷移之前存在的部分。目前,macOS 版本的 app,有 75% 是用 Swift 編寫的。

有趣的是,在我們剛開始用 Swift 時,就開始考慮放棄 Interface Builder。

太多的可變型別

在 Swift 中使用 Interface Builder 會帶來很多 optional(Swift 中的可選型別),而且它們都不屬於型別安全的域。我也不是僅僅在討論 outlets,如果你在 Storyboards 中使用 segues,你的資料模型中的 property 也會變成可選型別。事情就是在這裡變得不受控制。你的 view controller 是要求 property 正常工作的,現在它們變成了 optional,你就開始到處寫 guard,開始變得混亂,考慮在哪裡能夠優雅地處理它們,哪裡能簡單地從 fatalError 中逃脫出來。這是很容易出錯的,而且會明顯地降低程式碼的可讀性。

你的 view controller 是要求 property 正常工作的,現在它們變成了 optionals,你就開始到處寫 guard

……除非你使用 Implicitly Unwrapped Optionals(隱式解析可選),使用操作符!。這在大多數時候是有用的,不會出現任何問題,但這樣感覺是在欺騙 Swift 平臺。我們大多數人相信,Implicitly Unwrapped Optionals 應該在極少數的場景下使用,而且在日常開發中是應該避免在 Storyboards 中使用。

設計的改變

在 Objective-C 寫佈局程式碼還不算太糟,但是使用 Swift 就變得更簡單了,並且最重要的是,更易讀。宣告 Auto Layout 的 constraints 很輕鬆也很漂亮,這要感謝像 Cartography 這樣的庫。

// 建立 property 時定義外觀表現
let editButton: NSButton = {
    let button = NSButton()
    button.bordered = false
    button.setButtonType(.MomentaryChange)
    button.image = NSImage(named: "icEdit")
    button.alternateImage = NSImage(named: "icEditSelected")
    
    return button
}()

…

// 用 Cartography 宣告 Auto Layout 限制
constrain(view, editButton, self) { view, editButton, superview in
    editButton.left == view.right
    editButton.right <= superview.right - View.margin
    editButton.centerY == view.centerY
}
複製程式碼

我猜想,我們可以將使用 Interface Builder 的開發者分為兩種型別:一類是隻用來做 Auto Layout 和 segues 的,一類是也會用來附加設計的;在 Interface Builder 設定顏色,字型和其他視覺化的屬性。

在使用 Interface Builder 時,你會發現你自己在複製貼上你之前寫好的檢視 —— 並且你都不會對這種行為感到不好。

我們 稍稍微地 屬於第二種型別 !Zeplin 是一個常變的 app,當只有設計元素改變的時候,這最終就開始困擾我們了。讓我們假設,你只需要改變一個公用按鈕的背景顏色。你需要開啟每一個 nib 檔案並且手動的改變它們。當這個需要經常重複的時候,你就會可能漏掉一些。

當你使用純程式碼來編寫檢視時,這會激勵你複用程式碼。正相反,在使用 Interface Builder 時,你會發現你自己在複製貼上你之前寫好的檢視 —— 並且你都不會對這種行為感到不好。

可複用的檢視

根據 Apple 的觀點,Storyboards 是未來。從 Xcode 8.3開始,我們在開發專案的時候,都沒有一個可以不使用 Storyboards 的選項。? 這確實很令人傷心,這都沒有一個直接了當的方法來複用 Interface Builder 中的檢視

這就是為什麼,我們發現自己一直用純程式碼來編寫一些常用的公共檢視。建立一個可以同時用程式碼和 nib 初始化的檢視也是棘手的,強制你去實現兩個構造器並且去做同樣的初始化行為。當你只是用程式碼時,你可以安全的忽略 _init?(coder: NSCoder)_

轉換背後

在轉換之後,我們有了一個認知:使用程式碼構建介面提升了我們對於 UIKitAppKit 元件的理解。

我們在轉換一些之前用 nib 實現的舊的功能。當我們嘗試去保留外觀,我們必須去學習更多的關於不同的屬性在做什麼和他們是如何影響一個組建的外觀。在之前,他們只是被 Interface Builder 預設設定的一些選擇和核取方塊,而且它們就這樣起作用了。

使用程式碼構建介面提升了我們對於 UIKitAppKit 元件的理解。

對於導航性的元件,像 UINavigationControllerUITabBarControllerNSSplitViewController 這些都是可行的。尤其對於新手來說,他們極其依賴於這些元件但又不是真正地理解它們在幕後是怎麼工作的。當你嘗試用程式碼來初始化和使用它們時,就會立即感覺很舒服。

[譯]沒有 Interface Builder 的生活

[譯]沒有 Interface Builder 的生活

Zo 在開啟一個龐大的 Storyboard 時很煎熬。

除錯的問題

是否曾有過一個 bug,你花費幾分鐘時間來追溯並且最終發現,造成它的原因是一個沒有被連線起來的 outlet 或者是 nib 中一個你無意中改變的選項?

每一個你用程式碼建立的元件都會被包在一個單獨的原始檔,因此你不需要去擔心在 nib 和原始檔之間的跳轉。這會幫助我們在除錯問題是更迅速,並且一開始就會引入更少的 bug。

程式碼稽核和合並衝突

為了讀懂和理解透徹 nib,你要不得是一個 nib 奇才,要不你就得花費相當多的時間!這就是為什麼**大多時間,人們都直接在稽核程式碼時略過 nib 的改動,因為它太嚇人了。**想一想這些潛在的可視的 bug 可能會因為在程式碼中使用常量和文字直接被消除掉。

在反對 nib 的聲音中,衝突的合併是你會最經常聽到的抱怨。如果你曾在一個使用 nib,尤其是 Storyboards 的專案中工作過,你可能也親身經歷過。你知道這通常意味著:一個人的工作會需要被回滾然後再重應用。這些事最令人煩躁的衝突,而且當你團隊變大時,會變得越來越讓人沮喪。你可以相應地分配任務,這在大多數時候可以克服這個問題。但在 Storyboards,即使在你單獨寫一個 ViewController 時,這樣的問題都可能發生。

出人意料的,當時這對於 Zepin 來說,不算是個問題 —— 因為我們是一個比較小的團隊,我猜。這也是為什麼我把這一點放到了最後來說。

結論

我已經列出了很多的原因來解釋為什麼停止使用 Interface Builder 是一個好主意,但別誤會,有一些用例下,使用 Interface Builder 也是有道理的。即使我們故意省略這些用例,因為我們目前,在沒有 Interface Builder 的情況下更加開心了。

不要害怕去實踐,並且去看看這是否也適合你們的工作流程!


感謝我們可愛的 @ygtyurtsever。讓我們知道你是怎麼想的,在下面留言吧!?


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章