kelsheikh
kelsheikh

Reputation: 1338

Pass data from a button in reused custom cell

I'm having trouble passing data from a custom cell by a user tapping a button in that custom cell. I sometimes get the wrong cells data since the cell is being reused. I was wondering if there was a full proof way to always get the right cell data to its button in each cell no matter which cell is currently on the screen. Below is my code. Any help is greatly appreciated.

My Custom Cell:

protocol CustomCellDelegate {
  func segueWithCellData()
}

class CustomTableViewCell : UITableViewCell {
  var delegate = CustomCellDelegate?

  @IBAction func buttonTapped() {
    if let delegate = self.delegate {
        delegate.segueWithCellData()
     }
   }
}

MyTableViewController:

class MyTableViewController : UITableViewController, CustomCellDelegate {
   var posts = [Post]()
   var title: String!

   override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let post = posts[indexPath.row]
      let cell =  tableView.dequeueReusableCellWithIdentifier("CustomCellReuseIdentifier", forIndexPath: indexPath)
      title = post.title

    cell.delegate = self        

    return cell
}

   func segueWithCellData() {
     self.performSegueWithIdentifier("passMyData", sender: self)
   }

   override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
     if segue.identifier == “passMyData” {
        let destination = segue.destinationViewController as! UINavigationController
        let targetVC = destination.topViewController as! nextVC
        targetVC.title = title    
      }

    }
 }

Upvotes: 5

Views: 152

Answers (4)

Mahesh Agrawal
Mahesh Agrawal

Reputation: 3358

Full proof solution which i have used in almost all apps. Create a custom property of type NSIndexPath in a category class of UIButton and assign the indexPath in cellForRowAtIndexPath function. Now in the callback of the button find the object at index by the buttons indexPath.row from the datasource. this never fails.

Upvotes: 1

Bista
Bista

Reputation: 7893

My Custom Cell:

protocol CustomCellDelegate {
  func segueWithCellData(cell:CustomTableViewCell)
}

class CustomTableViewCell : UITableViewCell {
  var delegate = CustomCellDelegate?

  @IBAction func buttonTapped() {
    if let delegate = self.delegate {
        delegate.segueWithCellData(self)
     }
   }
}

CustomCellDelegate Method:

func segueWithCellData(cell:CustomTableViewCell) {
    //Get indexpath of selected cell here
    let indexPath = self.tableView.indexPathForCell(cell)
    self.performSegueWithIdentifier("passMyData", sender: self)
}

Hence, no need of tagging cell. Since, you have indexPath of the selected cell, you can get data from this and pass this through sender parameter of performSegueWithIdentifier method.

For example,

func segueWithCellData(cell:CustomTableViewCell) {
    //Get index-path of selected cell here
    let selectedIndexPath = self.tableView.indexPathForCell(cell)
    let post = posts[selectedIndexPath.row]

    self.performSegueWithIdentifier("passMyData", sender: post)
}

and, get the data inside prepareForSegue as follows:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
     if segue.identifier == “passMyData” {
        let destination = segue.destinationViewController as! UINavigationController
        let targetVC = destination.topViewController as! nextVC

        //Get passed data here
        let passedPost = sender as! Post

        targetVC.title = title    
      }
}

Upvotes: 2

user3849220
user3849220

Reputation:

Simple solution: fill the tableView from an array (String) and update the tableView. If you want change some datas in the tableView you need to update your array and refresh the tableView.

I use this solution in my applications and it works great.

Upvotes: 0

praths
praths

Reputation: 353

first you have to create a dictionary of index and titles like this in MyTableViewController:

var titleDict = [Int:String]()

set the tag of the cell to index in table view and append title to titleDict like this in MyTableViewController:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let post = posts[indexPath.row]
      let cell =  tableView.dequeueReusableCellWithIdentifier("CustomCellReuseIdentifier", forIndexPath: indexPath)
      title = post.title

    let index = indexPath.row
    cell.tag = index
    titleDict[index] = title
    cell.delegate = self        

    return cell
}

and pass the tag value of that cell in cell delegate method like this in My Custom Cell:

protocol CustomCellDelegate {
  func segueWithCellData(index:Int)
}

class CustomTableViewCell : UITableViewCell {
  var delegate = CustomCellDelegate?

  @IBAction func buttonTapped() {
    if let delegate = self.delegate {
        let index = self.tag
        delegate.segueWithCellData(index)
     }
   }
}

and access the title from the titleDict with the given index from delegate method and set to title variable in MyTableViewController:

func segueWithCellData(index:Int) {
     if let title = titleDict[index]{
        self.title = title
     }
     self.performSegueWithIdentifier("passMyData", sender: self)
   }

Upvotes: 0

Related Questions