將 child view controller 存成方便存取的 property

開發 iOS App 時,有些 controller 是 container view controller,它負責控制管理其它的 view controller。這些被它控制的 controller 就像它的小孩,因此又被稱為 child view controller。

在 container view controller 的程式裡,我們時常會需要存取 child view controller,比方傳資料給 child view controller,或是呼叫 child view controller 的 function。

為了能方便存取 child view controller,以下我們介紹兩種方法:

  • 在 viewDidLoad 讀取 property children,將 child view controller 存成方便存取的 property
  • 在 prepare 讀取 segue.destination,將 child view controller 存成方便存取的 property

假設 storyboard 的設計如下,使用者在 ViewController 頁面透過 segmented control 切換顯示小貓列表或小狗列表。ViewController 是 container view controller,它利用兩個 container view 連結 CatTableViewController & DogTableViewController,因此 CatTableViewController & DogTableViewController 是 ViewController 的 child view controller。

在 ViewController 的程式裡,我們先宣告 property catTableViewController & dogTableViewController。我們的目標是將 storyboard 連結的 child view controller 存入 catTableViewController & dogTableViewController,之後即可在程式裡方便地存取它們。

class ViewController: UIViewController {
var catTableViewController: CatTableViewController!
var dogTableViewController: DogTableViewController!

方法 1: 在 viewDidLoad 讀取 property children,將 child view controller 存成方便存取的 property

class ViewController: UIViewController {
var catTableViewController: CatTableViewController!
var dogTableViewController: DogTableViewController!
override func viewDidLoad() {
super.viewDidLoad()

children.forEach {
switch $0 {
case let controller as CatTableViewController:
catTableViewController = controller
case let controller as DogTableViewController:
dogTableViewController = controller
default:
break
}
}

print(catTableViewController, dogTableViewController)
}
}

UIViewController 的 property children 儲存著 child view controller,它的型別是 [UIViewController]。我們利用 children.forEach 讀出每個 child view controller,判斷型別後分別存入 catTableViewController & dogTableViewController。

方法 2: 在 prepare 讀取 segue.destination,將 child view controller 存成方便存取的 property

class ViewController: UIViewController {
var catTableViewController: CatTableViewController!
var dogTableViewController: DogTableViewController!

override func viewDidLoad() {
super.viewDidLoad()

print(catTableViewController, dogTableViewController)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destination {
case let controller as CatTableViewController:
catTableViewController = controller
case let controller as DogTableViewController:
dogTableViewController = controller
default:
break
}

}
}

當 ViewController 的畫面顯示時,由於它的 2 個 container view 利用 segue 連結 CatTableViewController & DogTableViewController,因此會先觸發 function prepare(for:sender:) 2 次,然後再觸發 viewDidLoad。

我們在 prepare(for:sender:) 裡讀取 segue.destination,取得 segue 連結 CatTableViewController & DogTableViewController,將它們存入 catTableViewController & dogTableViewController。

由於程式執行的順序是先 prepare(for:sender:) 再 viewDidLoad,因此等到 viewDidLoad 執行時,catTableViewController & dogTableViewController 都會是有值的狀態。

參考連結

Apple’s Creating a Custom Container View Controller

Apple’s Explore a location with a highly detailed map and Look Around

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store