-1

My code works, but I'm trying to understand it. It's a bit of code used to manage a "Cancel" button that can return from either a "Show" segue (presented when user clicks on a table view cell for editing) or a "Present Modally" segue (when the user clicks a "+" bar button item to add a new cell to the table view). Diagram below. I'm getting confused by UINavigationController and the navigationController property. Apologies if I'm missing something very obvious.

// Apple says below is nil if neither the current view controller nor any of its ancestors were presented modally
let isPresentingInAddMode = presentingViewController is UINavigationController
if isPresentingInAddMode {
    // Modal segues need to be dismissed
    dismiss(animated: true, completion: nil)
} else {
    // But Show segues are "popped" off of a stack of controllers.
        navigationController!.popViewController(animated: true)
}

Here's what I am not understanding: - If I've arrived at the Detail View Controller via a "Show" segue, pause during execution, and option-click on navigationController, Xcode says that it's a UINavigationController? And if I pause execution inside the else condition & use the debugger to: po navigationController! == nil - Xcode says it this evaluates to false, so navigationController is a valid UINavigationController.

So why doesn't

presentingViewController is UINavigationController 

equate to true in the topmost statement when I've presented using a "Show"?
Perhaps I'm not understanding "present". Is presenting something that only happens with modal segues, so there's no presentingViewController? And if I look back at my storyboard (see diagram below) one of the ancestors for the Detail View Controller is a table view controller that has a navigation controller embedded in it given Apple's definition of presentingViewController, shouldn't: presentingViewController is UINavigationController Be true in this situation, too?

And would:

presentingViewController != nil

achieve the same result or is there an important reason to verify the presentingViewController is a UINavigationController?

Thanks much for anyone kind enough to help me parse this out. John

enter image description here

enter image description here

The "ShowDetail" segue is a "Show" segue originating from the table view cell. The "AddItem" segue is of kind "Present Modally" and is originating from the "+" add bar button item.

It's likely not necessary to see the prepare for segue code in the table view controller, but if you're curious:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    if segue.identifier == "ShowDetail" {  // is this the "ShowDetail" segue? and if it is...
        // ... get the IndexPath for the row the user clicked on (the selected row)
        let indexPath = tableView.indexPathForSelectedRow!
        let destinationViewController = segue.destination as! DetailViewController // downcast the destination as the specific class DetailViewController
        // Get the to do item that the user clicked on
        let selectedToDo = toDoArray[indexPath.row]
        // Pass selectedToDo to the toDoItem variable in our destinationViewController
        destinationViewController.toDoItem = selectedToDo
    }
}
Gallaugher
  • 1,593
  • 16
  • 27
  • please add code where you call the ViewControllers – muescha Jan 28 '17 at 17:03
  • put shot code snippets between two of this char: ` (backtick) – muescha Jan 28 '17 at 17:04
  • Hi - there is a Show segue - "ShowDetail" is its identifier. "AddItem" is called from the "+" add bar button item, while "ShowDetail" is called from the table view cell. I'll add the "prepare(for segue:) code for the table view controller above, but it shouldn't matter re: understanding the UINavigationController vs. navigationController, should it? Thx – Gallaugher Jan 28 '17 at 17:15
  • Yes - poor choice of Identifier name by me, but "ShowDetail" is the identifier. The segue is of Kind: attribute is "Show (e.g. Push)". – Gallaugher Jan 28 '17 at 17:29

1 Answers1

2

Perhaps I'm not understanding "present".

Perhaps. Let's consult the chart:

enter image description here

There are two commonly used built-in segues:

  • Show, formerly known as Push. If used in a UINavigationController situation, as intended, calls pushViewController. The pushed view controller has a navigationController. The return is performed by calling popViewController.

  • Present, formerly known as Modal. Calls presentViewController (now called present). The presented view controller has a presentingViewController. The return is performed by calling dismiss.

However, there's a complication that can confuse you: if show is used not in a UINavigationController situation, instead of the universe exploding as expected, it magically turns itself into present.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Unfortunately, people in speaking informally do very often say "present" when they mean "push", so you have to watch out. – matt Jan 28 '17 at 17:36
  • This was great! Very helpful. So modals always have a presentingViewController. Is it appropriate to use either of these two statements to test if a view controller is modal? "presentingViewController != nil" or "presentingViewController is UINavigationController"? – Gallaugher Jan 28 '17 at 17:48
  • Almost. Look more carefully at what I said. Asking whether `self.presentingViewController != nil` is how to learn whether `self` is a presented view controller. Asking whether `self.navigationController != nil` is how to learn whether `self` is a pushed view controller. — In general, however, you will never _not_ know this, so in practice the question doesn't usually arise. – matt Jan 28 '17 at 17:55
  • Thanks again. This code confusion comes from my attempt to learn Swift using Apple'sFoodTracker app. Looks like the ShowDetail misname was learned from Cupertino :) https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementEditAndDeleteBehavior.html#//apple_ref/doc/uid/TP40015214-CH9-SW1 – Gallaugher Jan 28 '17 at 18:25
  • No. Look more carefully at the screen shot. `"ShowDetail"` is merely an arbitrary string here: the segue's string _identifier_. It could just as well have been `"RevealTheDetailsToMe"`. The segue _itself_ is a Show segue, as you can see from the Kind pop-up just below. – matt Jan 28 '17 at 18:56
  • Thanks - just bought Kindle version of your "Programming iOS 10: Dive Deep into Views, View Controllers, and Frameworks". Your kindness on StackOverflow pays off :) Best, J – Gallaugher Jan 28 '17 at 21:13