0

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: enter image description here which is segued back to the PinViewController (VC3) via self.performSegueWithIdentifier("backToPins", sender: self)

How can I do this?

GarySabo
  • 5,806
  • 5
  • 49
  • 124
  • You simply use an unwind segue. Define the unwind method in VC3 and the magic is managed for you – Paulw11 Apr 24 '16 at 14:55
  • Thanks @Paulw11 unwindForSegue will get me to VC3, but I need VC3 to be "refreshed" with the new model data that was added in VC5, so I'm not sure unwinding to the previous instance of VC3 is best here, I think I need a new instance with the updated model data? – GarySabo Apr 24 '16 at 17:58
  • You can pass data back through an unwind segue; the `unwind` method receives a `UIstoryboardSegue` that has a `sourceViewController` which you can use just like the `destinationViewController` in `prepareFoeSegue` – Paulw11 Apr 24 '16 at 21:16

2 Answers2

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 :)

Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
  • Thank you! Is prepareForSegue called on popToViewController though? I do need to pass a var back to VC3.... – GarySabo Apr 24 '16 at 17:50
  • no prepareforsegue is not called on poptoviewcontroller. you can use protocol and delegate to pass data back. google it "pass data back to viewcontroller" you will get many links. :) – Ketan Parmar Apr 24 '16 at 17:56
1

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

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Thanks @Paulw11 the problem I have with unwind segue is the `someFunctionThatUpdatesScene()` the VC is a collectionView controller and reloading, invalidating layout doesn't work. You are sent back to the exact cells that were on the screen when you left. I essentially need to "refresh" the entire collectionViewController but I haven't been able to figure out if that's possible – GarySabo Apr 24 '16 at 21:31
  • Why wouldn't it be? The unwind function is in VC3 and you know which cell you were editing (you can save a property that tells you that if you need to) so it is trivial to access the data from the VC5 instance and reload the appropriate cell(s) – Paulw11 Apr 24 '16 at 21:33
  • It's a little more involved...the cells in VC3 were populated via an async network call, then VC5 deletes and replaces the data and posts it to the network...so I'm not just editing local data, I need VC3 to make a new network call inside unwindSegue to acquire the updated data, then reload the collectionView...which I haven't been able to get to work. – GarySabo Apr 24 '16 at 21:37
  • You should be able to do that, but it isn't very efficient. It would be better for VC5 to update the network and the local shared data model which both VC3 and VC5 are accessing. It doesn't make sense to read things back from the network which you just wrote. It unnecessarily uses data transfer and battery – Paulw11 Apr 24 '16 at 21:39
  • Good point and that's probably my next TODO, but at this point I wasn't keeping any data local since this is the only manipulation of the data in my app. – GarySabo Apr 24 '16 at 21:42
  • The most obvious reason that you may not be able to get the updated operation when you return to vc3 is that the update is asynchronous in vc5 and so at the point you try and read it from the network, the update has not yet completed. Another reason why you should use local data. – Paulw11 Apr 24 '16 at 21:49
  • I'm working with an API, so I don't have the ability replace the data on the network in large chucks (i.e. keep a local array, edit the local array, then replace the network array with the local array), I can only post a new edited piece of data at a time. – GarySabo Apr 24 '16 at 23:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110083/discussion-between-paulw11-and-garysabo). – Paulw11 Apr 24 '16 at 23:58