Search code examples
iosswiftsprite-kitsegueskscene

Segue from SKScene to storyboard creating instances of old scene


Here is my storyboard showing a segue to a UINavigationController:

enter image description here

I fade out my game scene and call this segue from my SKScene like so:

mainVC?.performSegue(withIdentifier: "tySeg", sender: nil)

The nav controller moves a UIViewController on top of the game scene, as expected. But during the transition, I can see two new instances of the SKScene popping up in the background before the transition finishes and they are covered up by the new view controller. A print statement in my scene's didMove(to view:) method confirms that an SKScene object is appearing twice.

I can't figure out why my SKScene subclass is automatically being called twice after it triggers a segue. I also tried presenting the view controller like so but had the same issue:

mainVC?.present(navVC, animated: false, completion: nil)

I have a cludgy workaround in mind but I'd rather understand what is causing this to happen so I can prevent it. Any ideas?

UPDATE:

I suspect the reason has something to do with a passage from this Apple doc:

When presenting a view controller using the UIModalPresentationFullScreen style, UIKit normally removes the views of the underlying view controller after the transition animations finish. You can prevent the removal of those views by specifying the UIModalPresentationOverFullScreen style instead. You might use that style when the presented view controller has transparent areas that let underlying content show through.

When using one of the full-screen presentation styles, the view controller that initiates the presentation must itself cover the entire screen. If the presenting view controller does not cover the screen, UIKit walks up the view controller hierarchy until it finds one that does. If it can’t find an intermediate view controller that fills the screen, UIKit uses the root view controller of the window.

You can see in my screenshot that GameViewController is my initial view controller. This is where I am calling the segue from. Like the doc says, maybe UIKit is removing the underlying content (the SKView that is presenting my game scene) when the segue is called. But I am using a full-screen presentation style, and UIKit requires that the scene's view controller must cover the screen. Since it was removed by UIKit, then UIKit goes up the view hierarchy and finds GameViewController which it calls to display.

I'm making a lot of assumptions, but seems like that might explain why my game scene is being recreated twice (or once... I had different results in my testing) while it calls a segue and waits for the transition to finish.

Also, I noticed that if I change the segue I'm using from Show to Present Modally, Over Full Screen, then the issue does not occur. That seems to support my guess.


Solution

  • Well, after our conversation it turns out that it uses the same instance of GameViewController. So in your case you just workaround it. It's happening because your second view controller somehow not covering the entire screen (or it has opacity), and the system layout again the GameViewController. As you quoted:

    When using one of the full-screen presentation styles, the view controller that initiates the presentation must itself cover the entire screen. If the presenting view controller does not cover the screen, UIKit walks up the view controller hierarchy until it finds one that does. If it can’t find an intermediate view controller that fills the screen, UIKit uses the root view controller of the window.

    For others i'll keep some of the old answer:

    When you segue to a view controller you always creates a new instance. (So if you want to reuse the instance, don't use segues!)

    When you present, you always shows it modally.

    When you show you move to another view controller.