UIViewControllerの画面構成・画面遷移まとめ (iPhone向け)

UIKit による iOSアプリの画面は１つ以上の UIViewController で構成され、画面遷移も UIViewController により行われます。また、UIViewController間の関連性は UIViewController のプロパティにより把握することができます。

この記事では iPhone 向けの画面構成・画面遷移、そしてその関連性について整理してまとめたものです。主に iPad 向けの Split View や Popover については触れません。

### 1. UIViewController
1つの UIViewController だけで構成される最もシンプルな状態。

```swift
let viewControllerA = UIViewController()
window.rootViewController = viewControllerA
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/be611e28-7be5-b163-663e-52886c3ab02f.png)

### 2. UIViewController → UIViewController (Present Modally)
UIViewController の `present(_:, animated:)` メソッドにより、別の UIViewController をモーダル表示。

```swift
let viewControllerA = UIViewController()
window.rootViewController = viewControllerA

let viewControllerB = UIViewController()
viewControllerA.present(viewControllerB, animated: true)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/2f67cbe9-2d42-f719-3c78-f3758ef7fdb7.png)

- `viewControllerA.presentedViewController` → `viewControllerB`
- `viewControllerB.presentingViewController` → `viewControllerA`

### 3. UIViewController → UIViewController (Embed)
UIViewController に別の UIViewController を組み込み、コンテナとして振る舞う。

```swift
let viewControllerA = UIViewController()
window.rootViewController = viewControllerA

let viewControllerB = UIViewController()
viewControllerA.addChild(viewControllerB)
viewControllerA.view.addSubview(viewControllerB.view)
viewControllerB.didMove(toParent: viewControllerA)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/bcbea930-eb2a-9b45-8e7e-03b6f9b2899b.png)

- `viewControllerA.children ` → `[viewControllerB]`
- `viewControllerB.parent ` → `viewControllerA`

### 4. UINavigationController → UIViewController (Root) → UIViewController (Show Detail)
UINavigationController という特殊な UIViewController。複数の UIViewController を扱うコンテナとして振る舞い、ドリルダウン形式の画面遷移を行う。

```swift
let viewControllerA = UIViewController()
let navigationController = UINavigationController(rootViewController: viewControllerA)
window.rootViewController = navigationController

let viewControllerB = UIViewController()
viewControllerA.navigationController?.pushViewController(viewControllerB, animated: true)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/bcd405fb-3c19-d219-84e3-412ceb34d128.png)

- `navigationController.children` → `[viewControllerA, viewControllerB]`
- `navigationController.viewControllers` → `[viewControllerA, viewControllerB]`
- `navigationController.topViewController` → `viewControllerB`
- `navigationController.visibleViewController` → `viewControllerB`
- `viewControllerA.parent` → `navigationController`
- `viewControllerA.navigationController` → `navigationController`
- `viewControllerB.parent` → `navigationController`
- `viewControllerB.navigationController` → `navigationController`

### 5. UINavigationController → UIViewController (Root) → UIViewController (Show Detail) → UIViewController (Present Modally)
UINavigationController から別の UIViewController をモーダル表示。

```swift
let viewControllerA = UIViewController()
let navigationController = UINavigationController(rootViewController: viewControllerA)
window.rootViewController = navigationController

let viewControllerB = UIViewController()
viewControllerA.navigationController?.pushViewController(viewControllerB, animated: true)

let viewControllerC = UIViewController()
viewControllerB.present(viewControllerC, animated: true)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/b67fe864-b296-f2f2-f601-71a11a3d982c.png)

- `navigationController.children` → `[viewControllerA, viewControllerB]`
- `navigationController.viewControllers` → `[viewControllerA, viewControllerB]`
- `navigationController.topViewController` → `viewControllerB`
- `navigationController.visibleViewController` → `viewControllerC`
- `navigationController.presentedViewController` → `viewControllerC`
- `viewControllerA.parent` → `navigationController`
- `viewControllerA.navigationController` → `navigationController`
- `viewControllerA.presentedViewController` → `viewControllerC`
- `viewControllerB.parent` → `navigationController`
- `viewControllerB.navigationController` → `navigationController`
- `viewControllerB.presentedViewController` → `viewControllerC`
- `viewControllerC.presentingViewController` → `navigationController`

### 6. UITabBarController → [UIViewController, UIViewController]
UITabBarController という特殊な UIViewController。複数の UIViewController を扱うコンテナとして振る舞い、タブ形式の画面遷移を行う。

```swift
let tabBarController = UITabBarController()
window.rootViewController = tabBarController

let viewControllerA = UIViewController()
let viewControllerB = UIViewController()
tabBarController.viewControllers = [viewControllerA, viewControllerB]
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/d5686ff9-f9e0-fdbe-74ed-b1f5db89a671.png)

- `tabBarController.children` → `[viewControllerA, viewControllerB]`
- `tabBarController.viewControllers` → `[viewControllerA, viewControllerB]`
- `tabBarController.selectedViewController` → `viewControllerA`
- `viewControllerA.parent` → `tabBarController`
- `viewControllerA.tabBarController` → `tabBarController`
- `viewControllerB.parent` → `tabBarController`
- `viewControllerB.tabBarController` → `tabBarController`

### 7. UITabBarController → [UIViewController, UIViewController] → UIViewController (Present Modally)
UITabBarController から別の UIViewController をモーダル表示。

```swift
let tabBarController = UITabBarController()
window.rootViewController = tabBarController

let viewControllerA = UIViewController()
let viewControllerB = UIViewController()
tabBarController.viewControllers = [viewControllerA, viewControllerB]
tabBarController.selectedIndex = 1

let viewControllerC = UIViewController()
viewControllerB.present(viewControllerC, animated: true)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/7a468006-a34c-6918-1385-58a39f5c35b3.png)

- `tabBarController.children` → `[viewControllerA, viewControllerB]`
- `tabBarController.viewControllers` → `[viewControllerA, viewControllerB]`
- `tabBarController.selectedViewController` → `viewControllerB`
- `tabBarController.presentedViewController` → `viewControllerC`
- `viewControllerA.parent` → `tabBarController`
- `viewControllerA.tabBarController` → `tabBarController`
- `viewControllerA.presentedViewController` → `viewControllerC`
- `viewControllerB.parent` → `tabBarController`
- `viewControllerB.tabBarController` → `tabBarController`
- `viewControllerB.presentedViewController` → `viewControllerC`
- `viewControllerC.presentingViewController` → `tabBarController `  


### 8. UITabBarController → [UIViewController, UINavigationController → UIViewController (Root) → UIViewController (Show Detail)]
UITabBarController と UINavigationController の組み合わせ。

```swift
let tabBarController = UITabBarController()
window.rootViewController = tabBarController

let viewControllerA = UIViewController()
let viewControllerB = UIViewController()
let navigationController = UINavigationController(rootViewController: viewControllerB)
tabBarController.viewControllers = [viewControllerA, navigationController]
tabBarController.selectedIndex = 1

let viewControllerC = UIViewController()
navigationController.pushViewController(viewControllerC, animated: true)
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/c9eb2af4-7831-1aa0-72e2-9d55851341ea.png)

- `tabBarController.children` → `[viewControllerA, navigationController]`
- `tabBarController.viewControllers` → `[viewControllerA, navigationController]`
- `tabBarController.selectedViewController` → `navigationController `
- `viewControllerA.parent` → `tabBarController`
- `viewControllerA.tabBarController` → `tabBarController`
- `navigationController.parent` → `tabBarController`
- `navigationController.tabBarController` → `tabBarController`
- `navigationController.children` → `[viewControllerB, navigationControllerC]`
- `navigationController.viewControllers` → `[viewControllerB, navigationControllerC]`
- `navigationController.topViewController` → `viewControllerC`
- `navigationController.visibleViewController` → `viewControllerC`
- `viewControllerB.parent` → `navigationController`
- `viewControllerB.navigationController ` → `navigationController`
- `viewControllerB.tabBarController ` → `tabBarController`
- `viewControllerC.parent` → `navigationController`
- `viewControllerC.navigationController ` → `navigationController`
- `viewControllerC.tabBarController ` → `tabBarController`