將 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