Programmatically defining a new navigation control

2019-01-29 11:28发布

问题:

I have a NavigationController that the following VC's are embedded in: VC1 -> VC2 -> VC3 -> VC4 -> VC5. My problem is that when I segue from VC5 (after editing is completed), I send you back to VC3, but I want to programmatically throw VC4 and VC5 off the stack, i.e. when the user is sent back to VC3, I want "back" in the navagitionBar to take you to VC2 (and not VC5 where you really came from).

This comes up a lot in IOS, where you want to edit the model, then send them back to the tableView/Collection view, but since editing is done, you don't want the editing viewControllers in the navigation stack anymore as its too confusing of UX.

In the screenshot below, the VC on the top right is VC5: which is segued back to the PinViewController (VC3) via self.performSegueWithIdentifier("backToPins", sender: self)

How can I do this?

回答1:

don't use segue to come back (pop).

you should use popToViewController and pass specific viewcontroller as argument to pop that viewcontroller.

for example if you want to go on 3rd view controller out of five then you can do something like below. you can just change index from viewcontroller array to go different view controller.

let viewControllers: [UIViewController] = self.navigationController!.viewControllers as [UIViewController];
self.navigationController!.popToViewController(viewControllers[viewControllers.count - 3], animated: true);

If you are using segue that means you add (push) new viewcontroller to navigation stack. in your example your stack after reaching 5th view is like,

VC1 - VC2 - VC3 - VC4 - VC5 (top of stack)

now if you performsegue to go back to VC3 then stack should be like this,

VC1 - VC2 - VC3 - VC4 - VC5 - VC3(top of stack)

and if you pop to VC3 then your stack is like,

VC1 - VC2 - VC3 (top of stack).

so pop viewcintrollers to go back don't use segue

hope this will help :)



回答2:

The best way to do this is via an unwind segue.

In VC3 you define an appropriate unwind function:

@IBAction func unwind(segue:UIStoryboardSegue) {
    if let sourceViewController = segue.sourceViewController as? VC5 {
         let myNewData=sourceViewController.someProperty
         self.someFunctionThatUpdatesScene()
}

Then in the VC5 scene you can create an unwind segue in one of two ways.

If you want it to be triggered directly from an object, such as a UIButton, you drag from the action in the inspector to the exit icon at the top of the scene and select unwind from the pop up.

If you want to trigger the unwind programatically then you drag from the view controller object in the explorer on the left to the exit icon and select unwind from the popup. You will now see an unwind segue in the explorer and you can give it an identifier like you would with any segue. You can use this identifier with performSegueWithIdentifier

The advantage of this approach is that you don't need to make any assumptions about the depth of UINavigationController stack and you don't need to implement a delegate/protocol to pass data back.

Apple has a very good Tech Note on Using Unwind Segues