Search code examples
iosuitableviewswift3uistoryboardsegue

Sending specific values from a TableViewCell to a ViewController by Perform Segue


I'm trying to show the details of a promotional coupon with information that comes from a TableViewCel into a View Controller by Performing a Segue.

this is my code in the cellForRowAt indexPath method and also de Perform Segue Function:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


    let coupons = [couponImage1, couponImage2, couponImage3, couponImage4, couponImage5, couponImage6, couponImage7, couponImage8, couponImage9, couponImage10]
    let couponsTitle = [couponTitle1, couponTitle2, couponTitle3, couponTitle4, couponTitle5, couponTitle6, couponTitle7, couponTitle8, couponTitle9, couponTitle10]
    let couponsDescription = [couponDesc1, couponDesc2, couponDesc3, couponDesc4, couponDesc5, couponDesc6, couponDesc7, couponDesc8, couponDesc9, couponDesc10]
    let couponsCategory = [couponCat1, couponCat2, couponCat3, couponCat4, couponCat5, couponCat6, couponCat7, couponCat8, couponCat9, couponCat10]

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeTableViewCell

    cell.couponImg.image = coupons[indexPath.row]
    cell.couponTitle.text = couponsTitle[indexPath.row]
    cell.couponDescription.text = couponsDescription[indexPath.row]
    cell.couponCategory.text = couponsCategory[indexPath.row]

    if indexPath.row == 0 {
        self.sendCouponImg = couponImage1
        self.sendCouponTitle = couponTitle1
        self.sendCouponDesc = couponDesc1
        self.sendCouponCat = couponCat1
    } else if indexPath.row == 1 {
        self.sendCouponImg = couponImage2
        self.sendCouponTitle = couponTitle2
        self.sendCouponDesc = couponDesc2
        self.sendCouponCat = couponCat2
    } else if indexPath.row == 2 {
        self.sendCouponImg = couponImage3
        self.sendCouponTitle = couponTitle3
        self.sendCouponDesc = couponDesc3
        self.sendCouponCat = couponCat3
    } else if indexPath.row == 3 {
        self.sendCouponImg = couponImage4
        self.sendCouponTitle = couponTitle4
        self.sendCouponDesc = couponDesc4
        self.sendCouponCat = couponCat4
    } else if indexPath.row == 4 {
        self.sendCouponImg = couponImage5
        self.sendCouponTitle = couponTitle5
        self.sendCouponDesc = couponDesc5
        self.sendCouponCat = couponCat5
    } else if indexPath.row == 5 {
        self.sendCouponImg = couponImage6
        self.sendCouponTitle = couponTitle6
        self.sendCouponDesc = couponDesc6
        self.sendCouponCat = couponCat6
    } else if indexPath.row == 6 {
        self.sendCouponImg = couponImage7
        self.sendCouponTitle = couponTitle7
        self.sendCouponDesc = couponDesc7
        self.sendCouponCat = couponCat7
    } else if indexPath.row == 7 {
        self.sendCouponImg = couponImage8
        self.sendCouponTitle = couponTitle8
        self.sendCouponDesc = couponDesc8
        self.sendCouponCat = couponCat8
    } else if indexPath.row == 8 {
        self.sendCouponImg = couponImage9
        self.sendCouponTitle = couponTitle9
        self.sendCouponDesc = couponDesc9
        self.sendCouponCat = couponCat9
    } else if indexPath.row == 9 {
        self.sendCouponImg = couponImage10
        self.sendCouponTitle = couponTitle10
        self.sendCouponDesc = couponDesc10
        self.sendCouponCat = couponCat10
    }

    return cell

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if(segue.identifier == "couponsDetails"){
        let viewController:DetailCouponsViewController = segue.destination as! DetailCouponsViewController
        viewController.getCouponsImage = self.sendCouponImg
        viewController.getCouponsTitle = self.sendCouponTitle
        viewController.getCouponsDescription = self.sendCouponDesc
        viewController.getCouponsCategory = self.sendCouponCat
    }
}

And this is the code at the Second View Controller:

class DetailCouponsViewController: UIViewController {
 @IBOutlet weak var couponCategory: UILabel!
 @IBOutlet weak var couponTitle: UILabel!
 @IBOutlet weak var couponImage: UIImageView!
 @IBOutlet weak var couponDescription: UITextView!
 @IBOutlet weak var couponLongDescription: UITextView!
 @IBOutlet var starButtons: [UIButton]!


var getCouponsTitle : String = ""
var getCouponsDescription : String = ""
var getCouponsCategory : String = ""
var getCouponsImage : UIImage? = nil

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(false)
    self.couponCategory.text = getCouponsCategory
    self.couponDescription.text = getCouponsDescription
    self.couponLongDescription.text = getCouponsDescription
    self.couponTitle.text = getCouponsTitle
    self.couponImage.image = getCouponsImage
}

My issue is that the data appearing on the Details View Controller is not the correct one, when I click the first row on the HomewTableViewCell is throwing the values that comes at the third row, and it's all mixed up. Does anyone can tell me what am I doing wrong please?


Solution

  • cellForRowAt function's purpose is to create a cell object which is a view, configure it and then display them. When you scroll down, this method is called so that the next cell will be prepared and then displayed. So if you set your variables in this function like that, the values in these variables are from the last cell that the tableView is prepared for display.

    For example, table view has 10 rows with variable foo values from 0 to 9. Your screen can display only 3 cells. When your view is loaded, your table view will call cellForRow three times to prepare views for cell 0 1 and 2 to be displayed. Since cell 2 is processed in the end, from your code, your local variable will have value 2. Then when you click on the first cell, you passed value 2 into the next view controller.

    To make it right, with the purpose of this function, first you need to move the definition of the array outside because you don't want to recreate then every time when a cell is prepared. Plus you will also need to access the arrays from another function when the cell is clicked. Given that your array data comes from a http request, first create variables outside to be empty arrays.

    var coupons: [String] = []
    var couponsTitle: [String] = []
    var couponsDescription: [String] = []
    var couponsCategory: [String] = []
    

    Then in your HTTP callback, add value to these arrays and then call tableView.reloadData() to reload the table with data from the server

    func yourHTTPCallBack() {
        //coupons = [foo1, foo2 ...]
        tableView.reloadData()
    }
    

    In your cellForRow, you are only displaying the cell, instead of saving any value to the local variables. Because click hasn't happened yet!

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeTableViewCell
    
        cell.couponImg.image = coupons[indexPath.row]
        cell.couponTitle.text = couponsTitle[indexPath.row]
        cell.couponDescription.text = couponsDescription[indexPath.row]
        cell.couponCategory.text = couponsCategory[indexPath.row]
    
        return cell
    }
    

    Then say you want to trigger segue when clicked on a cell, use this function from table view delegate

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.sendCouponImg = coupons[indexPath.row]
        self.sendCouponTitle = couponsTitle[indexPath.row]
        self.sendCouponDesc = couponsDescription[indexPath.row]
        self.sendCouponCat = couponsCategory[indexPath.row]
    
        //Do your segue here
    }