讓我們透過 container 來分離 ViewController 的職責吧
想必寫過 iOS 的人都有聽過 Massive View Controller 這個東西吧。在過去,我們常常會把整個畫面以及邏輯都寫在某個 ViewController 中,而這個 ViewController 就會像個垃圾場,因為不管什麼樣的邏輯都是寫在其中,同時也在 ViewController 來實現。
而為了解決這個問題,也誕生了 MVC 與其他衍生的設計模式 MVVM、MVP、VIPER 等等。然後,再把一些不需要寫在 ViewController 中的功能獨立出來,像是網路請求,本地資料存取等。而大家的目的都是把一些不需要的功能抽離,讓每個區域各司其職。
通常我們程式的複雜度,會隨著時間的增長而增加,如果沒有妥善管理這些複雜的邏輯時,那麼再修正錯誤時就會手忙腳亂。而我在前面隕石小故事有提到,我們可以把一些不需要寫在 ViewController 的功能抽離,自己獨立一塊讓整體的「職責分離」,而在畫面上我們有一個很好的元件,那就是 ContainerView
。
透過 ContainerView
我們可以將其他 Controller Embed 到其中,有點像是這個 ContainerView
就是一個小型的 ViewController
,除了一些畫面的資料傳遞除外,它就只處理這一區塊的功能和畫面,我們就是藉由這點使其職責分離。
這邊我們打算做一個 APP,只有一個畫面,並且同時需要 CollectionView
和 TableView
在畫面上,我們打算將我們 ViewController
中關於 TableView 和 CollectionView
的畫面和操作搬移到各自的檔案中處理:
而只有使用 Storyboard 開發才會有
ContainerView
這個元件可以使用,其他的開發方式只能透過程式碼來建立這個 Container 的操作。
基本上看到這個 Storyboard 的畫面就大概了解整個 ViewController
架構,也能清楚了解劃分的功能(UIView 的地方為 ContainerView
):
基本上,上面的 ContainerView
我們會用 CollectionViewController
取代原有的 CollectionView
,而下面的 ContainerView
使用 TableViewController
取代原有的 TableView
。
而我們一樣可以在屬性列的 Custom Class 來設定其 class
:
而使用程式碼建立 ContainerView
的方式,可以看下列這幾篇文章:
而大概會是像這樣的建立方式:
我們首先會透過 addChild
將指定的 ViewController
添加為當前 ViewController
的子級,等同於 ChildViewController
。接著設定其 constarint 填滿 containerView,最後將透過 didMove 通知 ChildViewController 已經被加入到 ParentViewController 中。
接著我們已經獨立出兩個 ContainerViewController
了,現在你已經可以在上面個別進行一些操作了,不需要在 ViewController 上面進行編寫,我們試著在兩個 Controller 上,簡單新增一些東西吧:
而我們的 ViewController
並沒有編寫任何程式碼,或許根本甚至不需要它,但是因為我們之後會透過 ViewController
來對這兩個 Controller 操作,所以我們暫時將它保留:
這們為了之後可以藉由 ViewController 操作其他兩個 Controller,我們會使用個別使用一個屬性將兩個 Controller 存儲在其中,透過 reference 的方式操控它們:
用程式碼建立 ContainerViewController
的話,我們可以在設定其 ChildViewController
時,同時賦予給我們的 tableVC
或 collectionVC
。但是如果是使用 Storyboard 該怎麼獲取呢?
首先我們可以透過 children
這個屬性來獲取目前所有的 ChildViewController
,之後可以透過判斷式來判斷該類型是否相等於我們 ContainerViewController
,分別賦予不同屬性,這邊我們簡單透過 type
的方式,將 ChildViewController
的類型印出給大家看看:
其實我們在 Storyboard 上看到這個 Segue,同時你也可以設定它的 identifier:
因此我們也可以透過 prepare
來獲取它,你可以透過 identifier
來判斷是哪個 segue,接著獲取其 destination
:
你也可以直接透過判斷 segue.destination
的 Type 是否為某個 Controller,如此一來就能直接判斷後直接使用:
如此一來你可以想像原有的 ViewController
現在唯一個中心控制器,它可以藉由 tableVC
和 collectionVC
兩個屬性來控制兩個 ChildViewController
,所以我們可以在 prepare
中進行一些基本設置及 delegate 之類的操作,最後我們 ViewController
整體的程式碼如下:
你可以看到我們的 ViewController
不會編寫到 CollectionView
或 TableView
接收什麼資料或是該怎麼呈現的方式,他只負責將所需資訊傳遞到各自的 Controller 中。
最後讓我們來 Demo 一下吧!我們會最透過上方的 CollectionView
滑動來更改下方 TableViewController
中的資料:
透過 Container 的方式,可以讓你將一些 MassiveViewController 中的部分邏輯抽離出來,藉由這種方式讓每個區塊各自處理畫面的顯示以及資料的串接等等其他邏輯,而最後我們主要的 ViewController
則是負責不同 ChildViewController
之間資料的溝通以及一些 Delegate 之類的操作。