2

enter image description here

I'm making an app which has a shopping cart feature. The shopping cart VC is accessible from several VCs via a button on the navigation bar. So far I only have one Navigation Controller and as shown in the image, each VC takes me to the next one, nothing fancy. The 3rd VC (blue arrow pointing to) is a VC that shows the product/item's details and enables me to add it to the cart.

Problem comes with the Shopping Cart VC. To edit the item, I'd like to re-use the same product/item's details (blue arrow pointing to) VC I used earlier.

Right now, I don't really have an issue but I have noticed that once I created the blue segue, the Navigation Bar of the 3rd VC disappeared in the Storyboard however I was still able to see it when I ran the app.

NOTE:

  1. All the segues in the picture are "Show"
  2. The shopping cart VC doesn't have a button to show itself like the other 3 does. So technically I prevented endless/loop of the shopping cart VC - product/item details VC showing one another.

My questions are:

  1. Is it wrong to design the app that way with a VC going to another VC and that other VC can go back to the first VC? Am I going to face issues down the road, perhaps memory leaks of some sort?
  2. Is there a better way to achieve what I am trying to achieve?

If someone needs further explanation please let me know and I'll edit my question.

EDIT: To clarify, the blue segue is basically a button in a UITableView in the cart VC. If you tap that button, it should open the product/item details VC and lets you edit the item's color, etc. In the item details VC, instead of adding the item as a new item to the cart, I'd show an Edit button which would send the edit request to the API and dismiss the VC back to the shopping cart, or I could use the back button in the navigation controller to get back to the shopping cart.

EDIT2: @beshio

Thanks for the answer. However VC1 is actually my root VC where all the app starts. I didn't get why removed VCs from the Navigation Controller's stack. I would like the Back button to work as intended.

So far I have achieved what I wanted but I'm afraid that having two VCs segue-ing to each other would cause a problem. I have already disabled the Cart button in VC3 in case VC3 was presented from the Cart so loops would be prevented. I am only worried about any memory leaks down the road.

Tarek
  • 783
  • 10
  • 31
  • What is a blue segue? Do the cardVC close itself or it creates new VC when trigger? – kirander Nov 13 '17 at 23:22
  • @kiranderI edited my question with more details. – Tarek Nov 13 '17 at 23:26
  • Hi @Tarek. I explained my answer EXACTLY as your chart says. Your chart doesn't have a transition that goes back to VC1 from anywhere. To achieve it, we need to remove the "path" to go back to VC1. My code demonstrates how to do it. In the same way, you can achieve ANY transition (VC* to VC*) by manipulating navigation stack as I demonstrated. Pls let me know if it's not clear how. You'd better to update your chart to the one you want. One more thing. With my code, back button and left-to-right swipe both works as you expect, after you manipulated the stack. – beshio Nov 15 '17 at 15:19

2 Answers2

2

It's possible to achieve this kinda transition.

Here, I describe how to implement this with your chart. As your chart shows, assume you have VC1, VC2, VC3 (top to bottom) and VCX (w/ blue box). You need to define transitions and associated animation directions (push: right-to-left or pop:left-to-right). As your chart, if you define the transitions and animations as:

  1. VC1 to : VC2(push), VCX(push)
  2. VC2 to : VC3(push), VCX(push)
  3. VC3 to : VCX(push)
  4. VCX to : VC3(pop)

and assume we have all of the view controllers instantiated already, then,

  • VC1 to VC2 transition

at VC1:

navigationController!.pushViewController(VC2, animated: true)

at VC2:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // remove VC1 from navigation stack (I assume VC1 is not a root VC)
    let allControllers = NSMutableArray(array: navigationController!.viewControllers)
    allControllers.removeObject(at: allControllers.count - 2)
    navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
 }
  • VC1 to VCX transition

at VC1:

navigationController!.pushViewController(VCX, animated: true)

at VCX: (A)

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let allControllers = NSMutableArray(array: navigationController!.viewControllers)
    if (navigationController!.viewControllers[allControllers.count-2] != VC3) {
        // if not from VC3, remove VC from stack and put VC3
        allControllers.removeObject(at: allControllers.count - 2)
        allControllers.insert(VC3, at: allControllers.count - 1)
        navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
    }
  • VC2 to VC3 transition

at VC2:

navigationController!.pushViewController(VC3, animated: true)

at VC3: (B)

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let allControllers = NSMutableArray(array: navigationController!.viewControllers)
    if (navigationController!.viewControllers[allControllers.count-2] == VC2) {
        // if from VC2, remove it
        allControllers.removeObject(at: allControllers.count - 2)
        navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
    }
}
  • VC2 to VCX transition

at VC2:

navigationController!.pushViewController(VCX, animated: true)

at VCX: same as (A)

  • VCX to VC3 transition

at VCX:

navigationController!.popViewController(animated: true)

at VC3: same as (B)

Note viewDidAppear is called when users swipe (left-to-right) to go back and cancel it on the way (== swipe back to left). So, you need some more small code at viewDidAppear against that situation.

If you want the different animation direction, by manipulating stack and using push/pop, you can easily achieve it. This explains how.

beshio
  • 794
  • 2
  • 7
  • 17
0

Awesome.

In these scenarios you should use setViewControllers([UIViewController], animated: Bool) to get the desired viewcontrollers in the stack when you get many controllers stacked up in cycles.

Other way is you write your own class derived from UINavigationController having methods, pushToCheckout(animated:Bool), popToEditCart(animated:Bool) , removeIntermediateControllers()

ahmed
  • 540
  • 2
  • 18