你為什麼不該在你的 iOS 軟體專案中使用 Storyboard

Storyboard 是蘋果從 iOS 5 起在 Xcode 開發工具中增加的新功能。

一直以來,無論是 Mac OS X 或是 iOS,都可以將應用程式所需要的介面呈現放在 nib 或是 xib 檔案中。我們可以用介面設計工具 Interface Builder(Xcode 4 整合到 Xcode 中),使用視覺化方式編輯 nib 或 xib 檔案,在程式執行時讓 runtime 將檔案中的 UI 定義轉換成對應的 Objective-C 物件。

因為之前有人問我為什麼有些 UIView subclass 在建立時會呼叫 initWithCoder:,而不是 initWithFrame:,其實並不難懂,這邊簡單解釋一下:nib 檔案是將 Objective-C 物件 serialize 成 binary data 的格式,所以用 nib 建立 UI,其實可以想成就是把 serialize 過的 data 再轉回物件;Objective-C 中負責處理物件/serialized data 相互轉換的物件叫做 NSCoder,所以你定義在 nib 裡頭的 view 在被建立時,呼叫到的就是 initWithCoder: 了,這套物件與資料轉換的機制,同時也是 Mac OS X 與 iOS 上實作 copy/paste 的基礎。而 xib 檔則是用 XML 格式表示 nib 檔的內容,在現在的開發流程中,平時我們會編輯 xib 檔案,但 xib 檔案會在 compile time 時被編譯成 nib 檔。

Storyboard 是這種視覺化開發方式的進一步發展。

在 iOS 5 之前,如果應用程式中有許多畫面,負責每個畫面的是各自的 view controller,在每個 view controller 中除了可以用程式碼撰寫建立 UI 物件外(實作 loadView: 這個 method),另一種方式則是讓每個 view controller 有各自對應的 nib 或 xib 檔案;Storyboard 則是將應用程式中原本有多個 nib 或 xib 檔案,合併成一個巨大的 XML,不但可以一次看到所有的畫面設計,也可以看到每個畫面之間透過線條串連起來的關係。或許可以這麼說:Storyboard 除了是一套畫面的設計工具外,也是一套說明在時間中畫面如何變化的敘述工具。

不過,在你的軟體開發專案中,建議不要使用 Storyboard。

理由有三:你的專案會變大,你會需要與其他人共事,以及,你還會同時或陸陸續續開發好幾個專案。

你的專案會變大

以我目前工作上在做的 iOS App 來說好了,先不管 iPad 的 UI,這個音樂播放程式在 iPhone/iPod Touch 上的 UI 組成,就有八十多個 view controller。應該算得上是個中型軟體的規模。

Screen Shot 2014-01-29 at 7.31.59 PM

當你的軟體規模到了一定程度之後,要想要改動程式、新增功能,如果不靠搜尋,要找到想要改動的地方就非常困難;在 Xcode 裡頭,除了可以對程式碼做關鍵字搜尋外,在左側的檔案列表也可以使用關鍵字過濾檔名。雖然 Storyboard 中也可以用關鍵字過濾物件,但是過濾方式又與你需要的不一樣,Storyboard 中是按照對於物件的名稱過濾,但你的需求可能是想要知道某個 Class 到底用在軟體裡的哪個地方,但 Xcode 中沒有這種過濾方式。

檔案變多之後,你也會使用群組的角度看事情,你不會逐一去看每個程式碼檔案/物件/畫面之間的關係,而是先把整個軟體的不同區塊切割成若干群組,先看大方向每個群組之間的關係,要細看每個畫面間的關係,也只會侷限在這一個群組的範圍內。以上面那張圖來說,是用 Graphviz 畫的,在畫的時候也是區分了六、七個 subgraph,不然完全無法整理全部的關係。但 Storyboard 並沒有 subgraph 的設計。

你不會同時編輯八十幾個 Class 的程式碼,但如果你使用 Storyboard,你只是想要改某個畫面的內容,卻需要同時顯示八十幾個畫面如何繪製。畫面一多,而你的開發機又稍微有些年紀,你可以立刻感受到 Xcode 運作變得非常緩慢,甚至 Xcode 根本沒辦法把這個 Storyboard 檔案開起來。

就算你有多少畫面,你在開發時,一次也只會改動一個畫面而已,你可能只有百分之一的時間有想要看到整個軟體每個畫面的需求,但這件事情會讓你其餘百分之九十九的時間都無比痛苦。

這邊引用一篇講怎麼畫 Wireframe 的文章

有些 UI 設計師會把 Wireframe 串成很大一張 Flow,這能快速了解每個頁面的層級順序。但這對 RD 來說就是個吃效能的怪物, Wireframe 結合 Flow 的圖片尺寸非常非常大張。要從這麼大張的圖找到其中某一格是自己想看的那頁很困難,負責刻介面的 RD 比較長時間盯著其中一頁在工作、而不是對著整大張 Flow 圖滿畫面亂跑。…這張圖會大到沒有人想去開它、看著圖上標示的去執行,即使 RD 必須照著 Wireframe 工作。

畫 Wireframe 的 UI 設計師都知道工程師沒辦法拿一張把所有畫面全部列出來的大圖工作,你自己幹嘛要去用這種工具?

你需要與其他人共事

隨著專案變大,也就代表著,這個軟體不會是只有一個人負責。你會開始導入版本管理系統(當然,就算只有一個人寫程式,其實也應該使用版本管理系統),然後一定會有機會同時有許多人想要改動同一個檔案,也就一定會遇到衝突。

如果是程式碼遇到衝突還算好解決,只要編譯不過,Compiler 可以告訴你問題到底出在程式的哪一個部分,你可以跟隨 Compiler 給你的錯誤訊息,拿紅燈當做指引,便能一步一步 solve conflict。但如果遇到 conflict 的是 XML 這類的文件,那就麻煩了,Xcode 就只會告訴你無法開啟,而無法提供任何修正的建議。

當你沒有辦法處理衝突,另外一種可行的方式是,只選擇衝突中其中一方所做的更動,至少可以讓檔案格式正確、可以被打開,但這也就代表你必須捨棄另外一方所做的修改,也就是,其中有一方會做白工。

或是,團隊中約定好,一次只能夠只有一個人可以改動 UI,當有人決定改動 UI 的時候,其他人都不許改 Storyboard 的 XML 檔案,避免衝突—但這種分工完全不可行,例如,你這次改版沒有動到 Model 層,全都是 UI 的改版,而需要改動的地方一個人一定做不完,你怎麼能不讓多人同時改動 UI Code?

無論是花很多力氣手動改 XML 檔案 solve coflict、捨棄一部分改動好解決 conflict,或是避免多人同時改 UI 避免 conflict,都是生產力的浪費。

你還會有其他的專案

你一定會同時或陸續參與好幾個不同的軟體開發專案。如果你在接案公司,你可能每個星期都會接到不同的案子,如果你的公司有自有的產品,隨著業務需要也會開拓出新的產品線,或是覺得自己的產品也可以重新包裝一下幫別人 OEM,新的產品線也一定沒辦法每次都找到新的人來做,而是會用到既有人力。

而你一定可以發現,即使多麼不同的專案,也總是有共通的地方,為了開發效率,你會想要 reuse 曾經寫過的程式碼。你可能會把想共用的程式碼包成一個 library,可能變成一個 git submodule,或是一個 CocoaPods 套件,總之,你會希望只要把程式碼放進去,新的專案就直接擁有曾經寫過的功能。

但,如果你每個專案都使用 Storyboard,造成的結果就是,即使好幾個專案都共用了同一個 view controller class,但是 view controller 管理的 UI 元件卻分別定義在不同專案的 Storyboard 中,如果你升級了這個 view controller,你還要對不同專案中的 Storyboard 分別手動修改一次。也就是,使用 Storyboard 會妨礙程式碼重用/共用。

總之,當你的軟體規模、團隊成員、專案數量不斷成長時,使用 Storyboard 都會造成妨礙。那你或許會問,如果是在開發一個預估不會成長的軟體,使用 Storyboard 是不是能夠節省時間呢?我想我會這麼回答—如果你選擇開發的是一個不會成長的專案,這件事情就你的公司或你個人而言,其實就是在浪費時間。

Be Sociable, Share!

8 thoughts on “你為什麼不該在你的 iOS 軟體專案中使用 Storyboard

  1. 你好,常常在MacDev板學習您的文章。請問如果每個群組都獨立成一個storyboard呢?例如使用tabbar controller來區分功能的App,每個tab所需的頁面都獨立成一個storyboard,再透過instantiateViewControllerWithIdentifier:或instantiateInitialViewController將各storyboard的view controller整合在一起,這樣的方式還是不建議使用storyboard嗎?感謝

    • 這種作法會遇到的問題則是,如果在多個 Storyboard 中都用到了同一個 View Controller,那麼這個 View Controller 的 IBOutlet 又要怎麼定義?每個 Storyboard 都定義一次?這樣也會很辛苦。

      • 對於此文的結論,我持完全相反的意見。

        使用 multi-storyboard 的想法是對的,關鍵在於怎麼切分。

        按功能區分、妄想在長週期開發裡做 reuse 恐怕不太現實。假設真的所開發的 App 大到超過單一 storyboard 該承載的量(不過這種情形我就很懷疑該 App 有沒有很好的減法管理),第一次的切分 by scenario 來區分是比較建議的方式,這是同時顧及測試及需求校正的方式。在進入後來的 iteration 時,可以再視真實存在的需求把需要 reuse 的部分區分出另一個 storyboard。storyboard 的重構的確是個可以好好發揮的題材。

        至於重複使用 view controller 的部分,其實不是 issue。因為該再進一步封裝的是 controller 中的邏輯,而不是 controller 本身。在較大規模的系統裡,controller 本來就是較單純穿針引線就好。

        總之,storyboard 應該並不會「不該」被使用。這點我完全持相反的意見。再一次強調,以短周期的產品/專案來看,storyboard 用的再差,都沒關係,反正維護時間不長;若是長周期的產品來看,要能延伸、測試、追溯,這些都更是使用應該 storyboard 的原因才是!只是差別在:會不會好好用罷了。

        Xcode 5 開始在建立 single view project 已經不提供是否使用 storyboard 的選項了,必有其道理。

Leave a Reply