iosswiftxcodesegueunwind-segue

How to get unwind segue to work between along side a regular segue in the same view controller?


Sorry if the title is a little vague. I'm still learning swift and segues and I have 3 view controllers called EarthViewController, MoonViewController, and JupiterViewController.

These are the segues that work:

EarthViewController -> MoonViewController
MoonViewController -> JupiterViewController
JupiterViewController -> MoonViewController, 
and even JupiterViewController -> EarthViewController, 

but the unwind segue from MoonViewController -> EarthViewController keeps throwing a Thread 1: Signal SIGABRT error where I have commented //ERROR HERE when trying to go back to the Earth view. Here is the layout and code so far:

enter image description here

EarthViewController (ViewController)

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let des = segue.destination as! MoonViewController 

        if (segue.identifier == "toMoonView")
        {
            print("Went to the moon")
        }
    }

    @IBAction func backFromMoon(segue: UIStoryboardSegue){

        if let scVC = segue.source as? MoonViewController
        {
            print ("Back from the Moon to Earth")
        }
    }

    @IBAction func backFromJupiterToEarth(segue: UIStoryboardSegue){

        if let scVC = segue.source as? JupiterViewController
        {
            print ("Back from Jupiter to Earth")
        }
    }
}

MoonViewController

import UIKit

class MoonViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

//------------------------------------------------------------------------
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let des = segue.destination as! JupiterViewController //<- ERROR HERE

        if (segue.identifier == "toJupiterView")
        {
            print("Went to Jupiter")
        }
    }
//-----------------------------------------------------------------------
    @IBAction func backFromJupiter(segue: UIStoryboardSegue){

        if let scVC = segue.source as? JupiterViewController
        {
            print ("Back from Jupiter to the Moon")
        }
    }
}

JupiterViewController (Nothing added yet)

import UIKit

class JupiterViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }


}

Any help is greatly appreciated! Thank you!


Solution

  • This function in MoonViewController:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let des = segue.destination as! JupiterViewController //<- ERROR HERE
    
        if (segue.identifier == "toJupiterView")
        {
            print("Went to Jupiter")
        }
    }
    

    is called both for regular segues and unwind segues. When you are segueing to JupiterViewController then segue.destination is indeed of type JupiterViewController. But when you are unwinding to ViewController, segue.destination is of type ViewController.

    In this second case, the force cast as! JupiterViewController crashes because the type is wrong.

    One way to fix that is to move the declaration of des inside of the if when you have identified the destination:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toJupiterView"
        {
            let des = segue.destination as! JupiterViewController
            print("Went to Jupiter")
        }
    }