Lukas Bimba
Lukas Bimba

Reputation: 826

Swift Multiple buttons sending String through same segue

Looking for some clarification and just to double check if I am on the right path. I have a category list where multiple buttons will send a specific string through a segue. I have the IBOutlets for each button but want to make sure when that specific button is touched that specific string is sent. I am just unsure if the way I am setting up the segue is correct so that each button is specific to the set strings. So far, the current segue works for "attractionsButton" but when I tap other buttons it passes the same data. I know it's not set, but want to make sure that when another button is tapped its not sending the wrong string.

@IBOutlet weak var attractionsButton: UIButton!
@IBOutlet weak var eatingButton: UIButton!
@IBOutlet weak var financialButton: UIButton!
@IBOutlet weak var lodgingButton: UIButton!
@IBOutlet weak var medicalButton: UIButton!
@IBOutlet weak var publicButton: UIButton!
@IBOutlet weak var servicesButton: UIButton!
@IBOutlet weak var storesButton: UIButton!
@IBOutlet weak var transportationButton: UIButton!

let attractions = "Attractions & Entertainment"
let eating = "Eating & Drinking"
var financial = "Financial Institution"
var lodging = "Lodging Establishment"
var medical = "Medical & Health"
var publicService = "Public Services & Buildings"
var services = "Service"
var stores = "Stores & Shopping"
var transportation = "Transportation"


@IBAction func attractionsButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func eatingButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func financialButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func lodgingButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func medicalButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func publicButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func serviceButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func storesButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}
@IBAction func transportationButton(_ sender: Any) {
    performSegue(withIdentifier: "category", sender: self)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)
    if segue.identifier == "category" {
        if let button1 = attractionsButton {
            let user = attractions
            let controller = segue.destination as? CategoryListedViewController
            controller?.categoryList = user
        }
    }
}

Upvotes: 0

Views: 986

Answers (3)

Zaphod
Zaphod

Reputation: 7250

If I were you I would use buttons tags and a good old enum to work this out:

First, in Interface Builder, you set the tag property of each of your buttons (and you don't even need to have them anymore as @IBOutlet)

1 for attractionsButton, 2 for eatingButton, etc.

Then, you create an enum, with raw value as Int with matching values :

enum Category : Int, CustomStringConvertible {
    case attractions = 1
    case eating = 2
    case financial = 3
    case lodging = 4
    case medical = 5
    case publicService = 6
    case services = 7
    case stores = 8
    case transportation = 9

    var description : String {
        switch self {
        case .attractions: return "Attractions & Entertainment"
        case .eating: return "Eating & Drinking"
        case .financial: return "Financial Institution"
        case .lodging: return "Lodging Establishment"
        case .medical: return "Medical & Health"
        case .publicService: return "Public Services & Buildings"
        case .services: return "Service"
        case .stores: return "Stores & Shopping"
        case .transportation: return "Transportation"
        }
    }
}

After that, you link all your buttons to only one @IBAction like this one:

@IBAction func onButtonTap(_ sender: UIButton) {
    performSegue(withIdentifier: "category", sender: Category(rawValue: sender.tag))
}

This way, according to the tag of the button, you'll create the enum you need.

As an end, in your segue preparation, you can set things like that:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "category" {
        guard
            let controller = segue.destination as? CategoryListedViewController,
            let category = sender as? Category
            else { return }

        controller.categoryList = category.description
    }
}

This way, things are much more concise and you can attache more behaviors to your enum Category, use it in switches, and so on, instead of relying on Strings or multiplying copy&paste code.

Upvotes: 0

vacawama
vacawama

Reputation: 154513

All of your buttons can connect to just this one @IBAction:

@IBAction func allButtons (_ sender: Any) {
    performSegue(withIdentifier: "category", sender: sender)
}

Of course, if that is all the buttons are doing, you can skip using the @IBAction entirely and just wire the segues from the buttons directly. If you do that when creating the first button in the Storyboard, you can copy that button and all copies will be wired to the same segue.

Then in prepare(for:sender:), compare the sender to your @IBOutlets to set your string:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if let button = sender as? UIButton,
       let controller = segue.destination as? CategoryListedViewController,
       segue.identifier == "category" {

        let str: String

        switch button {
        case attractionsButton: str = attractions
        case eatingButton:      str = eating
        case financialButton:   str = financial
        default: str = ""
        }

        controller.categoryList = str
    }
}

Upvotes: 1

Parth Bhuva
Parth Bhuva

Reputation: 877

change self in your action to sender, you can use this one action for all the buttons

@IBAction func transportationButton(_ sender: Any) {
        performSegue(withIdentifier: "category", sender: sender)
}

use this code in your prepare for segue

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)
    if segue.identifier == "category" {

        let senderButton = sender as! UIButton

        switch senderButton{
        case attractionsButton:
            let user = attractions
            let controller = segue.destination as? CategoryListedViewController
            controller?.categoryList = user
        case eatingButton:
            //editing button scenario
            print("editing button scenario")
        default:
            //default code
            print("default scenario")
        }

    }
}

Upvotes: 2

Related Questions