6
votes

Problem Summary

My mainVC --> second VC transtion appears to run twice. However, what's odd is that the second VC's viewDidLoad only runs once. This is the only transition in my project that has this problem.

I have researched this and found load-twice issues but none are a match to my transition twice but load once scenario. Common issues, like someone having added two segues in the storyboard, do not appear in my project:

enter image description here

In my first/root view controller (called mainVC) I programmatically add an edge pan gesture in the viewDidLoad:

        let panLeftEdgeGesture_MainVC = UIScreenEdgePanGestureRecognizer(target: self, action: "panLeftEdge_toLifeList:")
        panLeftEdgeGesture_MainVC.edges = .Left
        view.addGestureRecognizer(panLeftEdgeGesture_MainVC)

When the user swipes that pan gesture, it triggers a function that calls a segue to my next VC. Problem is, that VC transition appears twice and then everything works fine after that. Nothing breaks or crashes. If I click my custom back button, the unwind back to mainVC only appears once.

Experiment to Shed Light on the Cause

Here's the weird part: in an attempt to understand what was understand, I inserted some println code and here's what the console prints:

No matching prepareForSegue: So did nothing to prepare.
LifeList_CollectionView viewDidLoad did run
Pan segue from mainVC to Life Lists did run
No matching prepareForSegue: So did nothing to prepare.

That first line is the prepareForSegue running. It says "did nothing" because in my prepareForSegue it checks which segue is running and sometimes it'll pass some code. In this case, the prepareForSegue does nothing but print that line.

The second line is the second VC's viewDidLoad running.

The third line seems weird and out of order to me, but I'm no expert. That println is in the mainVC and prints from the function called by the pan gesture, this is the function that triggered the segue in the first place. Why would this not print before the 2nd VC's viewDidLoad?:

func panLeftEdge_toLifeList(sender: UIScreenEdgePanGestureRecognizer) {
    performSegueWithIdentifier("segueToLifeLists", sender: nil)
    println("Pan segue from mainVC to Life Lists did run")
}

The fourth line is the mainVC's prepareForSegue running a second time. However, I don't see the console printing a second viewDidLoad, even though visually I see the transition happen twice.

Any idea what could cause such an odd behavior or, at the least, any tricks to stop this behavior?

4
Are you accessing the destination view controller's view anywhere within the source view controller? That would trigger it loading before the segue.user4151918
You mean via a protocol or something? Regardless, I think the answer's no. I pass it no data (hence no prepareForSegue code was necessary) and the 2nd VC doesn't conform to any delegate except the UICollectionView inside it.Dave G

4 Answers

11
votes

I had ALMOST the same problem and my second VC was sliding twice. The problem was with that segue arrow in my Main.storyboard. I control-dragged from a button in first VC and not from my VC (that little yellow circle on top of every VC), so I deleted that segue arrow and control-dragged from VC yellow circle to my second VC and it fixed the problem.

Also this is how I used performSegue function:

@IBAction func toSignUp(_ sender: Any) {
    performSegue(withIdentifier: "signUp", sender: nil)
}

Hope this was helpful.

0
votes

Essentially you simply need to rename the destination view controller's class.

For full answer see this post:

View Controller Loads Twice - How Do I Fix It?

0
votes

One reason might be that the controller which is being pushed have another transition in its viewWillAppear() method.

In my case, I had put textField.becomesFirstResponder() in viewWillAppear() method which triggers keyboard to show

Move any such method to viewDidAppear()

0
votes

I found Elena's answer (on this thread Pushing View Controller Twice) to be a time saving quick fix by simply checking if the navigation controller already contains the ViewController you want to push to.

if !(self.navigationController!.viewControllers.contains(editView)){
self.navigationController?.pushViewController(editView, animated:true)

}