iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 24
0
Mobile Development

諸神黃昏下的 iOS 工程師系列 第 24

D24 - 拿起次元切割刀,大卸八塊 ViewController

讓我們透過 container 來分離 ViewController 的職責吧

? 隕石小故事

想必寫過 iOS 的人都有聽過 Massive View Controller 這個東西吧。在過去,我們常常會把整個畫面以及邏輯都寫在某個 ViewController 中,而這個 ViewController 就會像個垃圾場,因為不管什麼樣的邏輯都是寫在其中,同時也在 ViewController 來實現。

而為了解決這個問題,也誕生了 MVC 與其他衍生的設計模式 MVVM、MVP、VIPER 等等。然後,再把一些不需要寫在 ViewController 中的功能獨立出來,像是網路請求,本地資料存取等。而大家的目的都是把一些不需要的功能抽離,讓每個區域各司其職。

Overview

通常我們程式的複雜度,會隨著時間的增長而增加,如果沒有妥善管理這些複雜的邏輯時,那麼再修正錯誤時就會手忙腳亂。而我在前面隕石小故事有提到,我們可以把一些不需要寫在 ViewController 的功能抽離,自己獨立一塊讓整體的「職責分離」,而在畫面上我們有一個很好的元件,那就是 ContainerView

透過 ContainerView 我們可以將其他 Controller Embed 到其中,有點像是這個 ContainerView 就是一個小型的 ViewController,除了一些畫面的資料傳遞除外,它就只處理這一區塊的功能和畫面,我們就是藉由這點使其職責分離。


|事前科普

這邊我們打算做一個 APP,只有一個畫面,並且同時需要 CollectionViewTableView 在畫面上,我們打算將我們 ViewController 中關於 TableView 和 CollectionView 的畫面和操作搬移到各自的檔案中處理:

而只有使用 Storyboard 開發才會有 ContainerView 這個元件可以使用,其他的開發方式只能透過程式碼來建立這個 Container 的操作。


|創建 CotainerView

基本上看到這個 Storyboard 的畫面就大概了解整個 ViewController 架構,也能清楚了解劃分的功能(UIView 的地方為 ContainerView):

基本上,上面的 ContainerView 我們會用 CollectionViewController 取代原有的 CollectionView,而下面的 ContainerView 使用 TableViewController 取代原有的 TableView

而我們一樣可以在屬性列的 Custom Class 來設定其 class

而使用程式碼建立 ContainerView 的方式,可以看下列這幾篇文章:

而大概會是像這樣的建立方式:

我們首先會透過 addChild 將指定的 ViewController 添加為當前 ViewController 的子級,等同於 ChildViewController。接著設定其 constarint 填滿 containerView,最後將透過 didMove 通知 ChildViewController 已經被加入到 ParentViewController 中。


|編寫 ContainerViewController

接著我們已經獨立出兩個 ContainerViewController 了,現在你已經可以在上面個別進行一些操作了,不需要在 ViewController 上面進行編寫,我們試著在兩個 Controller 上,簡單新增一些東西吧:

而我們的 ViewController 並沒有編寫任何程式碼,或許根本甚至不需要它,但是因為我們之後會透過 ViewController 來對這兩個 Controller 操作,所以我們暫時將它保留:


|獲取 ContainerView 的 ViewController

這們為了之後可以藉由 ViewController 操作其他兩個 Controller,我們會使用個別使用一個屬性將兩個 Controller 存儲在其中,透過 reference 的方式操控它們:

用程式碼建立 ContainerViewController 的話,我們可以在設定其 ChildViewController 時,同時賦予給我們的 tableVCcollectionVC。但是如果是使用 Storyboard 該怎麼獲取呢?

  1. 透過 children 查找 ChildViewController

首先我們可以透過 children 這個屬性來獲取目前所有的 ChildViewController,之後可以透過判斷式來判斷該類型是否相等於我們 ContainerViewController,分別賦予不同屬性,這邊我們簡單透過 type 的方式,將 ChildViewController 的類型印出給大家看看:

  1. 透過 segue 獲取 ChildViewController

其實我們在 Storyboard 上看到這個 Segue,同時你也可以設定它的 identifier:

因此我們也可以透過 prepare 來獲取它,你可以透過 identifier 來判斷是哪個 segue,接著獲取其 destination

你也可以直接透過判斷 segue.destination 的 Type 是否為某個 Controller,如此一來就能直接判斷後直接使用:

如此一來你可以想像原有的 ViewController 現在唯一個中心控制器,它可以藉由 tableVCcollectionVC 兩個屬性來控制兩個 ChildViewController,所以我們可以在 prepare 中進行一些基本設置及 delegate 之類的操作,最後我們 ViewController 整體的程式碼如下:

你可以看到我們的 ViewController 不會編寫到 CollectionViewTableView 接收什麼資料或是該怎麼呈現的方式,他只負責將所需資訊傳遞到各自的 Controller 中。

最後讓我們來 Demo 一下吧!我們會最透過上方的 CollectionView 滑動來更改下方 TableViewController 中的資料:


Summary

透過 Container 的方式,可以讓你將一些 MassiveViewController 中的部分邏輯抽離出來,藉由這種方式讓每個區塊各自處理畫面的顯示以及資料的串接等等其他邏輯,而最後我們主要的 ViewController 則是負責不同 ChildViewController 之間資料的溝通以及一些 Delegate 之類的操作。


上一篇
D23 - 還敢 Loading 啊~TableView!
下一篇
D25 - 使用 APP前,記得詳閱 PageViewController 說明書
系列文
諸神黃昏下的 iOS 工程師31

尚未有邦友留言

立即登入留言