Quang Dinh Luong
Quang Dinh Luong

Reputation: 113

Navigation error swift 3

I was trying to implement the cancel bar button as you can see from the image, which return to the previous viewController using dismiss, but when I click the button, nothing appears, do you know why?

enter image description here

Here's my code to implement that:

@IBAction func cancel(_ sender: UIBarButtonItem) {
    let isPresentingInAddTaskMode = presentingViewController is UINavigationController

    if isPresentingInAddTaskMode {
        dismiss(animated: true, completion: nil)
    }
    else if let owningNavigationController = navigationController{
        owningNavigationController.popViewController(animated: true)

    }
    else {
        fatalError("The AddTaskVC is not inside a navigation controller.")
    }
}

Thanks in advance.

Upvotes: 1

Views: 220

Answers (1)

tktsubota
tktsubota

Reputation: 9391

If I'm reading your question right, this is what your view controller hierarchy looks like:

For adding a new task:

Navigation Controller --(containing)--> "Managing Mode" --(modal)--> Navigation Controller --(containing)--> "Add New Task"

For editing a task:

Navigation Controller --(containing)--> "Managing Mode" --(push)--> "Add New Task"

The problem is that neither of your cases will actually work.

isPresentingInAddTaskMode

In the first case, we see this:

let isPresentingInAddTaskMode = presentingViewController is UINavigationController

if isPresentingInAddTaskMode {
    dismiss(animated: true, completion: nil)
}

I'd assume this would handle the case involving the modal presentation.

This will never be true, because presentingViewController is the "Managing Mode" view controller, not the navigation controller containing it or the navigation controller containing the "Add New Task" view controller.

Another problem with this is that you have to dismiss the navigation controller containing "Add New Task", not "Add New Task" itself. This means that instead of

dismiss(animated: true, completion: nil)

you would do

navigationController?.dismiss(animated: true, completion: nil)

owningNavigationController

In the second case, we see this:

else if let owningNavigationController = navigationController{
    owningNavigationController.popViewController(animated: true)
}

The first line makes sense: you're unwrapping the navigation controller. However, you then call popViewController(animated: true) on the navigation controller.

The problem with that is that both the modal and the push segues involve a navigation controller, so this case will work for both.

The Solution

You need to form a simpler cancel method using the above:

@IBAction func cancel(_ sender: UIBarButtonItem) {
    guard let owningNavigationController = navigationController else {
        fatalError("The AddTaskVC is not inside a navigation controller.")
    }

    if owningNavigationController.presentingViewController?.presentedViewController == owningNavigationController {
        // modal
        owningNavigationController.dismiss(animated: true, completion: nil)
    } else {
        // push
        owningNavigationController.popViewController(animated: true)
    }
}

This first unwraps the navigation controller and errors out if there is none, like what you did originally.

You then check, through a more complex way than before, if the modal segue occurred. This checks the navigation controller's presentingViewController and if it is itself. If so, it's modal and it dismisses itself. If not, it's a push segue and you pop the current view controller.

Upvotes: 1

Related Questions