Steven Stuu
Steven Stuu

Reputation: 63

Swift unwind segue in viewWillDisappear on NavigationBar back button clicked

I'm trying to change a label text with unwind segue in viewWillDisappear function. Every time the viewWillDisappear function is called, it automatically skips my unwind segue line instead of executing it.

I'm using Xcode 9 and Swift 4.2

These are my codes:

main page ViewController.swift

import UIKit
import Foundation

struct globalConstant {
   let lostMessage : String = "You Lost!"
   let welcomeMessage : String = "WELCOME"
   let playAgainMessage : String = "Play again"
   let resumeMessage : String = "Resume"
   let pausedMessage : String = "Game is paused"
   let playMessage : String = "Play Game"
}


class ViewController: UIViewController {

var globalConst = globalConstant()
var labelValue : String!

//start Outlet
@IBOutlet weak var mainLabel: UILabel!
@IBOutlet weak var startButton: UIButton!
//end Outlet


@IBAction func unwindFromGame(_ sender: UIStoryboardSegue){

    let gameController = sender.source as? gamePageViewController
    if (gameController?.balVariables.balanceValue)! <= 0{
    mainLabel.text = gameController?.balVariables.abc
    }
    else  {
        mainLabel.text = self.globalConst.pausedMessage
    }
  }
}

my second page gamePageViewController.swift

import UIKit
import Foundation

struct balanceVariables {
//declare var start
var initBalance : Int = 500
var balanceValue : Int = 0
let abc = "abc"
//declare var end
}

class gamePageViewController: UIViewController {

//   override func addChild(_ gamePageViewController: UIViewController) {

//   }

@IBOutlet weak var valueHolder: UILabel!

var balVariables = balanceVariables()

override func viewDidLoad() {
    super.viewDidLoad()

    //run on page load

    if balVariables.balanceValue <= 0 {
        balVariables.balanceValue = balVariables.initBalance
        valueHolder.text = String(balVariables.balanceValue)
    }else{
        balVariables.balanceValue = balVariables.balanceValue
    }

}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    performSegue(withIdentifier: "unwindFromGame", sender: self)
}


//    override func didMove(toParent ViewController: UIViewController?){
 //       performSegue(withIdentifier: "unwindFromGame", sender: self)
//    }

}

Here is the image of my storyboard configuration (for the unwind segue connection, I ctrl+dragged the View Controller icon to exit icon in gamePageViewController) StoryBoard Configuration

As mentioned, I couldn't get performSegue to run in viewWillDisappear. What I'm trying to achieve here is when I click the back button on NavigationBar, the viewWillDisappear will intercept and perform an unwind segue to the main ViewController which calls unwindFromGame and changes mainLabel.

From the code in gameViewController.swift, you'll notice that I have commented out didMove(toParent). Using this method, I could get my performSegue to run and it successfully retrieved the abc variable from gamePageViewController but the problem is that it loaded the page but didn't wait for my prompt on the back button. Instead it automatically ran didMove(toParent) and sent me back to my main screen with mainLabel edited. I've tried willMove(toParent) as well and I achieved the same result.

My questions are :

How do I get performSegue in viewWillDisappear to run?

Is this an iPhone X / iPhone Xs Max related issue?

Using didMove(toParent) or willMove(toParent), how do I get it to wait for my prompt on the back button?

Let's say it's not possible to get it to work with NavigationBar Back Button. Will a custom NavigationBar Back Button achieve expected result? If so, how should I do it?

Do you recommend switching to Swift 4 instead of 4.2?

Thank you very much.

Upvotes: 0

Views: 617

Answers (1)

Robert Dresler
Robert Dresler

Reputation: 11140

Let's try it with delegate pattern not with using unwind segue.

Firste create delegate protocol for your gamePageViewController and declare function for sending balanceVariables

protocol GamePageDelegate {
    func sendBalVariable(_ variable: balanceVariables)  
}

now create delegate variable in your gamePageViewController

class gamePageViewController: UIViewController {

    var delegate: GamePageDelegate?
    ...
}

Then implement this delegate to your ViewController and declare what should happen when you call this method on delegate

class ViewController: UIViewController, GamePageDelegate {
    ...
    func sendBalVariable(_ variable: balanceVariables) {
        if variable.balanceValue <= 0 {
            mainLabel.text = variables.abc
        } else {
            mainLabel.text = self.globalConst.pausedMessage
        }
     /* mainLabel.text = variable.balanceValue <= 0 ? variables.abc : self.globalConst.pausedMessage */
    }
}

now override prepare(for:sender:) in your ViewController and set destination's delegate as self (if segue's identifier matching with identifier of your segue between ViewController and gamePageViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "yourIdentifier" {
        let destinationVC = segue.destination as! gamePageViewController
        destinationVC.delegate = self
    }
}

Finally in your gamePageViewController call method on delegate when view will disappear and ass parameter pass balVariables

override func viewWillDisappear(_ animated: Bool) {
    delegate?.sendBalVariable(balVariables)
}

Upvotes: 1

Related Questions