# Navigation

So far, we've only worked with one screen which may contain many views. For this single screen, we controlled the models and views with a single `UIViewController`. However, many of the apps that we use today contain multiple screens that we can navigate between. In UIKit, we represent every distinct screen with a separate `UIViewController`. There are two ways to navigate between screens: 1) **pushing/popping** and 2) **presenting/dismissing**.

### Pushing/Popping

Before we dive in to the technical details, let’s observe what pushing and popping looks like.

<figure><img src="/files/WziZZbkx5NBj3PhoMgG5" alt="" width="188"><figcaption></figcaption></figure>

As we can see, when we tap on one of the cells, a new screen shows up. Each new screen that we push is a separate `UIViewController`. So then, how do we keep track of the view controllers that have been pushed to figure out which one needs to be popped? We use a **navigation stack**. Every time a view controller is pushed, it goes on top of the navigation stack. Think of the navigation stack as a stack of books where each book is a view controller. The last item to be pushed into this stack will be the first one to be popped out (LIFO). How do we represent this navigation stack in UIKit? We use a **`UINavigationController`**.

Inside of `SceneDelegate.swift` add this code to the function `scene`:

```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // 1. Capture the scene
    guard let windowScene = (scene as? UIWindowScene) else { return }
    
    // 2. Create a new UIWindow and pass in a UIWindowScene
    let window = UIWindow(windowScene: windowScene)
    
    // 3. Create a view hierarchy programmatically
    let rootVC = ViewController()
    let navController = UINavigationController(rootViewController: rootVC)
    
    // 4. Set the navigation controller as the window's root view controller
    window.rootViewController = navController
    
    // 5. Set the window and call makeKeyAndVisible()
    self.window = window
    window.makeKeyAndVisible()
}
```

The important step to remember here is step 3 where we first initialize the view controller (`rootVC`) that we want to be displayed when the app launches. Now, we have to place `rootVC` into the navigation stack by creating a `UINavigationController` with `rootVC` as the root view controller.

One thing to keep in mind is that the line `let rootVC = ViewController()` creates a view controller whose class name is `ViewController`. When we create a new project, by default, a class called `ViewController` is created for us. If we created a new class or renamed the class to `HomeViewController`, then we would use `HomeViewController()` instead.

Now, to push and pop a view controller is very simple:

```swift
// Push
navigationController?.pushViewController(_ viewController: UIViewController, animated: Bool)

// Pop
navigationController?.popViewController(animated: Bool)
```

`UIViewController` will be the view controller object that we want to push. Most of the time, we want to set `animated` to `true`. For example, if we had a class called `ProfileViewController` and wanted to *push* it, we would write the following code in the view controller class that is pushing it (not inside `ProfileViewController`):

```swift
let profileVC = ProfileViewController()
navigationController?.pushViewController(profileVC, animated: true)
```

To *pop* the `ProfileViewController`, we would write this code in `ProfileViewController`:

```swift
navigationController?.popViewController(animated: true)
```

We could then link this code to some action such as a tapping on a button, cell, image, etc.

### Presenting/Dismissing

Let’s observe what presenting and dismissing looks like.

<figure><img src="/files/taUKiOKbvdqhzhn2neJ3" alt="" width="188"><figcaption></figcaption></figure>

As we can see, a modal sheet is presented from the bottom of the screen and gradually transitions up. This is **presenting**. To **dismiss**, we can simply click on the cancel button or more commonly, swipe downwards from the top of the modal sheet. The view controller that is being presented is displayed on top of the previous view controller. **There is not a navigation stack at play here ⇒ No `UINavigationController`.**

To present/dismiss a view controller:

```swift
// Presenting
present(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)

// Dismissing
dismiss(animated: Bool, completion: (() -> Void)?)
```

For example, if we had a class called `ProfileViewController` and wanted to *present* it, we would write the following code in the view controller class that is pushing it (not inside `ProfileViewController`):

```swift
let profileVC = ProfileViewController()
present(profileVC, animated: true)
```

To *dismiss* the `ProfileViewController`, we would write this code in `ProfileViewController`:

```swift
dismiss(animated: true)
```

As we may have notice from the function header above, there is an optional parameter called `completion`. This is known as a **completion handler** which is a function that gets executed when the function call is complete. We will discuss this in detail once we get into networking.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/textbook/mvc-+-navigation-+-delegation/navigation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
