Search code examples
iosarraysswiftcontrol-flowfor-in-loop

how to make sure that my for in loop enables me to perform only one segue?


I have a tableview inside a view controller, that is connected to 3 different view controller by a segue. Each one has an identifier.

In order to perform a segue to the corresponding view controller, I have created an array that contains the identifiers for each segue. like so :

var tableauSegues = ["versChapitre1", "versChapitre2", "versChapitre3"]

In order to manage the segue according to the index of the array, I chose to use a for in loop inside of an iB action, like this:

@IBAction func versHistoire(_ sender: UIButton) {

    for i in tableauSegues {

        performSegue(withIdentifier: i, sender: self)
    }

}

the problem is that all 3 segues are performed. I only want to perform one segue at the time.

any idea ?


Solution

  • Obviously, you want to avoid looping, but instead want to just use tableauSegues[row]. But the trick is how to get the row.

    Bottom line, you should let the cell handle the tapping of the cell, and have the cell tell the table view controller when its button was tapped. But the trick is that when it does that, it should supply a reference to itself when it does that, so that the view controller can determine which row had its button tapped.

    Thus, remove your existing @IBAction directly between the button and the view controller, and instead, hook it up to an @IBAction in the cell’s base class.

    //  CustomCell.swift
    
    import UIKit
    
    protocol CustomCellDelegate: class {
        func didTapButton(_ sender: Any, in cell: CustomCell)
    }
    
    class CustomCell: UITableViewCell {
        @IBOutlet weak var customLabel: UILabel!
    
        static let preferredReuseIdentifier = "CustomCell"
    
        weak var delegate: CustomCellDelegate?
    
        func configure(text: String, delegate: CustomCellDelegate) {
            customLabel.text = text
            self.delegate = delegate
        }
    
        @IBAction func didTapButton(_ sender: Any) {
            delegate?.didTapButton(sender, in: self)
        }
    }
    

    Note, when I configure that cell, I’m going to have the table view provide not only whatever values need to be displayed in the cell, but also indicate that it is the delegate for that cell:

    //  ViewController.swift
    
    import UIKit
    
    class ViewController: UIViewController {
        @IBOutlet weak var tableView: UITableView!
    
        var tableauSegues = ["versChapitre1", "versChapitre2", "versChapitre3"]
    }
    
    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return tableauSegues.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.preferredReuseIdentifier, for: indexPath) as! CustomCell
            cell.configure(text: "...", delegate: self)
            return cell
        }
    }
    
    extension ViewController: CustomCellDelegate {
        func didTapButton(_ sender: Any, in cell: CustomCell) {
            let row = tableView.indexPath(for: cell)!.row
            let identifier = tableauSegues[row]
            performSegue(withIdentifier: identifier, sender: self)
        }
    }