How to pass UIButton's tag (an Int) to other ViewController using prepareForSegue (Swift 4, Xcode 9)

Viewed 968

I am building an iOS app with 2 ViewControllers, the first being StartViewController.swift, the second being ViewController.swift.

StartViewController shows a number of 9 UIButtons, to each of which I have assigned an individual tag in Xcode's attributes inspector, namely integers from 0 to 8.

Every button represents some topic that the user would want to learn more about. Accordingly there is another file in my project where I created an array of headings and corresponding texts that represent the relevant information I want to show the user. The second VC (ViewController.swift) has 2 UILabels that show heading and text respectively.

In short, I want to grab the button’s tag (an Int) and use ist to output the topic information with the according index in my array.

I have connected both VCs with a UIStoryboardSegue that I named startToTopicSegue. Then I implemented the prepare(for segue: ) method and set up the buttons. With print statements I have confirmed that 1) the sender.tag in StartViewController.swift is indeed the tag of the tapped button, and 2) that the tagPassedOver variable sets the heading and text labels in the ViewController.swift as it should.

But tagPassedOver is not affected by what I specified in viewDidLoad() at all, instead it keep the init value of 0 - how do I change that?

I have the strong feeling that it has something to do with the specification of the sender in the first VC, but right now I am kind of lost in translation here, so any help would be appreciated ;) - thank you!

StartViewController.swift

@IBAction func buttonPressed(_ sender: UIButton) {
    print(sender.tag)

    performSegue(withIdentifier: "startToTopicSegue", sender: UIButton.self)
}

func prepare(for segue: UIStoryboardSegue, sender: AnyObject) {
    if segue.identifier == "startToTopicSegue"{
        let destinationVC = segue.destination as! ViewController
        destinationVC.tagPassedOver = sender.tag
    }
}

ViewController.swift

var tagPassedOver : Int = 0

@IBOutlet weak var headingLabel: UILabel!
@IBOutlet weak var textLabel: UILabel!

override func viewDidLoad() {

    headingLabel.text = allTopics.list[tagPassedOver].topicHeading
    textLabel.text = allTopics.list[tagPassedOver].topicText
3 Answers

You should be passing the instance of the UIButton whose tag you need.

@IBAction func buttonPressed(_ sender: UIButton) { 
    print(sender.tag)
    performSegue(withIdentifier: "startToTopicSegue", sender: sender) // You have required button in sender, so pass that as sender
}

And in prepare method cast the sender to UIButton and retrieve it.

func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "startToTopicSegue"{
        let destinationVC = segue.destination as! ViewController
        if let button = sender as? UIButton {
            destinationVC.tagPassedOver = button.tag
        }
    }
}

you can send tag Int value in sender argument

performSegue(withIdentifier: "startToTopicSegue", sender: sender.tag)

and cast sender to Int value in prepare method

destinationVC.tagPassedOver = sender as! Int

As a follow up to Rakesha Shastri's answer, I would suggest using the below code format when implementing the prepare(for:sender:) segue method

func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if 
       let destination = segue.destination as? ViewController,
       let button = sender as? UIButton {
            destinationVC.tagPassedOver = button.tag
        }
    }
}

This makes use of the optionals core functionality by safely unwrapping the segue destination, rather than checking the segue's identifier and then force unwrapping its destination.

Related