Retrieve information from Table Cell? - swift

I have a custom UITableViewCell with 2 labels and a button. The cell has it's own class:
class personTableCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBAction func inviteButtonPressed(_ sender: Any) {
self.accessoryType = .checkmark
}
}
Inside the view controller that contains the table view, I add the cells to the table in this method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "person", for: indexPath) as? personTableCell
cell?.nameLabel.text = results[indexPath.row].name
cell?.emailLabel.text = results[indexPath.row].email
return cell!
}
When a user presses the button inside the cell that calls the #IBAction func inviteButtonPressed, I want to add the cell's labels' text into an array that's initialized in the same view controller as the table.
How can I achieve such a thing if the #IBAction func inviteButtonPressed is in a seperate file as the table's view controller?

I think using delegate is one of solutions.
In TableViewCell class
#objc protocol PersonTableViewCellDelegate {
func personTableViewCellInviteButtonPressed(cell: PersonTableViewCell)
}
class PersonTableViewCell: UITableViewCell {
weak var delegate: PersonTableViewCellDelegate?
#IBAction func inviteButtonPressed(_ sender: Any) {
delegate?.personTableViewCellInviteButtonPressed(cell: self)
}
}
In ViewController class
class TableViewController: UITableViewController, PersonTableViewCellDelegate {
var results: [Person] = []
var invited: [Person] = []
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "person", for: indexPath) as! PersonTableViewCell
cell.nameLabel.text = results[indexPath.row].name
cell.emailLabel.text = results[indexPath.row].email
cell.delegate = self
return cell
}
func personTableViewCellInviteButtonPressed(cell: PersonTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else {
return
}
let person = results[indexPath.row]
invited.append(person)
}
}

Related

Show hidden label by button click inside tableView Cell (expand/collapse cell)

I have a stackView(vertical) which contains labels and bottom description label is hidden by default. And I implemented an arrow button at the right side of the cell. By clicking the button, I just want to show the hidden description label and stackView should expand automatically and make cell bigger. This was my basic idea to implement expandable cell.
So this is the code I used to get desired results:
#objc func downArrowButtonClicked(_ sender: UIButton){
let indexPath = IndexPath(row: sender.tag, section: 0)
selectedIndex = indexPath
selectedCellIndex = sender.tag
isDescHidden = !isDescHidden
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Above is the code for the button inside clicked cell. I went with the idea to reload that particular index. I created a variable named selectedCellIndex of in which I use in cellForRowAt method to make some changes.
I also had the implement some code in viewDidLayoutSubviews() as when I first clicked the cell wasn't getting expanded fully. here's that just in case:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let indexPath = selectedIndex
tableView.reloadRows(at: [indexPath ?? IndexPath(row: 0, section: 0)], with: .automatic)
}
And calling it in willDisplay method which finally fixed the cell expansion issue:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
viewDidLayoutSubviews()
}
And here is my cellForRowAt function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
if indexPath.row == 0 {
cell.lblTitle.text = "Title 1"
cell.lblDesc.text = "Desc 1"
}
else if indexPath.row == 1 {
cell.lblTitle.text = "Title 2"
cell.lblDesc.text = "Desc 2"
}
else {
cell.lblTitle.text = "Title 3"
cell.lblDesc.text = "Desc 3"
}
if selectedCellIndex != nil {
if isDescHidden == false {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
else {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
}
else {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
else {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
}
cell.isDescHidden = !cell.isDescHidden
}
cell.btnArrow.tag = indexPath.row
cell.btnArrow.addTarget(self, action: #selector(downArrowButtonClicked(_:)), for: .touchUpInside)
return cell
}
This approach gets too confusing as you can see from the above code. The isDescHidden variable is defined in both Main view controller as well as table view cell class and I was trying to use both to expand or collapse a particular cell. However first time it works but if I have 3 cells expanded, collapsing button click doesn't work for 1-2 clicks then works.
Is there a better approach for this kind of problem? Or is there any way I can directly set cell.isDescHidden value from #objc func downArrowButtonClicked(_ sender: UIButton) function? So I can use that in cellForRowAt function?
I would be glad if I could directly make changes to cell variables from that.
Use the following function for automatic height for rows and provided top and bottom constraints to your stackView
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Here is my CustomCell
class CustomCell: UITableViewCell {
#IBOutlet weak var titleCell: UILabel!
#IBOutlet weak var detail: UILabel!
#IBOutlet weak var arrowButton: UIButton!
let upArrow = UIImage(systemName: "chevron.up.circle.fill")
let downArrow = UIImage(systemName: "chevron.down.circle.fill")
var onArrowClick: ((UIButton)->())!
#IBAction func handleArrowButton(sender: UIButton){
onArrowClick(sender)
}
func updateArrowImage(expandStatus: Bool){
arrowButton.setImage(expandStatus ? downArrow : upArrow, for: .normal)
}
}
For sample Data
let data = [
["Nothing", "description is very long description is very long description is very long description is very "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "]
]
var eachCellStatus: [Bool] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for _ in data {
eachCellStatus.append(true)
}
}
TableView methods are like this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
cell.titleCell.text = data[indexPath.row][0]
cell.detail.text = data[indexPath.row][1]
cell.detail.isHidden = eachCellStatus[indexPath.row]
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
cell.onArrowClick = { button in
self.eachCellStatus[indexPath.row].toggle()
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
tableView.reloadRows(at: [indexPath], with: .automatic)
}
return cell
}
First create a model to show data into cell. You have to preserve the state of cell.
struct CellData {
var title: String
var details: String
var isExpanded: Bool
}
In CustomTableViewCell add a property for cellData and assign Outlets data from it. Also create a protocol to reload row from UIViewController
protocol CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, flag: Bool)
}
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var detailsLabel: UILabel!
#IBOutlet weak var showButton: UIButton!
var indexPath: IndexPath?
var delegate: CustomTableViewCellDelegate?
var data: CellData? {
didSet {
if let data = data {
if data.isExpanded == false {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}else {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
titleLabel.text = data.title
detailsLabel.text = data.details
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
titleLabel.text = nil
detailsLabel.text = nil
}
#IBAction func showButtonAction(_ sender: UIButton) {
if var data = data {
data.isExpanded.toggle()
delegate?.reloadRow(cell: self, flag: data.isExpanded)
}
}
}
In UIViewController add an array of CellData type. You may assign it's data in viewDidLoad() method.
var tableData: [CellData]
Modify numberOfRowsInSection() and cellForRow() method like bleow.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
cell.data = tableData[indexPath.row]
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Then confirm CustomTableViewCellDelegate protocol to UIViewController
extension ViewController: CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, isExpanded: Bool) {
guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }
tableData[tappedIndexPath.row].isExpanded = isExpanded
tableView.reloadRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
}
}

UISwitches in UITableViewCell change states together

I have a very strange problem in my Swift project. I use UIswitch in my dynamic cells in my one-section uitable. Whenever I click on the 6th switch, the first one changes its state with it and vice versa. The .valueChanged function only works for the one that is clicked (correct behaviour).
I cannot figure out why the switches change state together.
This is the code for table cells:
import UIKit
class RoutineTableViewCell: UITableViewCell {
#IBOutlet weak var selectionSwitch: UISwitch!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var previewImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
and here is the code in my table view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RoutineTableReuseIdentifier, for: indexPath) as? RoutineTableViewCell
else{
return RoutineTableViewCell()
}
let exercise = section!.exercises[indexPath.row]
cell.title.text = exercise.title
cell.previewImage.image = UIImage(named: (exercise.gifName + ".gif"))
cell.selectionSwitch.addTarget(self, action: #selector(self.addRemoveExercise(_:)), for: .valueChanged)
return cell
}
#IBAction func addRemoveExercise(_ sender: UISwitch!) {
let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
if(sender.isOn){
customizedSection?.exercises[indexPath!.row] = section!.exercises[indexPath!.row]
}
else{
customizedSection?.exercises[indexPath!.row] = ExerciseModel()
}
}
Your tableView:
import UIKit
class TableViewController: UITableViewController,switchValues {
func changed(_ cell: UITableViewCell, _ mySwitch: UISwitch) {
let index = tableView.indexPath(for: cell)
switchStates[(index?.row)!] = mySwitch.isOn
tableView.reloadData()
}
var switchStates : [Bool] = [false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return switchStates.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.mySwitch.isOn = switchStates[indexPath.row]
cell.delegate = self
return cell
}
Your cell:
import UIKit
protocol switchValues {
func changed(_ cell:UITableViewCell,_ mySwitch:UISwitch)
}
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var mySwitch: UISwitch!
var delegate:switchValues!
#IBAction func valueChanged(_ sender: UISwitch) {
delegate.changed(self, mySwitch)
}
}

Swift: Change the cell's UIButton Image With tableView DidSelect method

I Have TableView with the two label and one UIButton inside the Tableview. So on DidSelect method i want to change the UIButton Image of that particular cell. As attach image.
Check This
import UIKit
class ButtonTblViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
var arry = ["Montitanki Chowk","Greenland Chokdi"]
var SelectData = [NSMutableDictionary]()
#IBOutlet weak var tbleVw: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<arry.count
{
self.SelectData.append(["data":arry[i],"isSelect":"NO"])
}
self.tbleVw.reloadData()
// Do any additional setup after loading the view.
}
// MARK - tableView Delegates
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return SelectData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:listTble = tableView.dequeueReusableCell(withIdentifier: "CellID", for: indexPath as IndexPath) as! listTble
cell.lblTit.text = self.SelectData[indexPath.row].value(forKey: "data") as? String
cell.btnRdo.tag = indexPath.row
let tapgesture = UITapGestureRecognizer(target: self , action: #selector(self.sectionTapped(_:)))
cell.btnRdo.addGestureRecognizer(tapgesture)
let selData = self.SelectData[indexPath.row].value(forKey: "isSelect") as! NSString
if selData == "NO" {
cell.btnRdo.setImage( UIImage(named: "btnUnSel"), for: .normal)
} else {
cell.btnRdo.setImage( UIImage(named: "btnSel"), for: .normal)
}
return cell
}
#objc func sectionTapped(_ sender: UITapGestureRecognizer){
if(self.SelectData[(sender.view?.tag)!].value(forKey: "isSelect") as! String == "NO"){
self.SelectData[(sender.view?.tag)!].setValue("YES", forKey: "isSelect")
}else{
self.SelectData[(sender.view?.tag)!].setValue("NO", forKey: "isSelect")
}
self.tbleVw.reloadData()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
class listTble: UITableViewCell {
#IBOutlet weak var lblTit: UILabel!
#IBOutlet weak var btnRdo: UIButton!
}
Out Put
you need to first set button tag in cellForRow method
after in didSelectRowAtIndexPath method you need to set image of button and in didDeselectRowAtIndexPath set unselect image in button.
you can set button image by using :
playButton.setImage(UIImage(named: "play.png"), forState:UIControlState.Normal)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let btn = (tableView.cellForItem(at: indexPath) as! yourCellName).button else {
return
}
btn.setImage(UIImage(named: "yourSelectedImage name"), for: .normal)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let btn = (tableView.cellForItem(at: indexPath) as! yourCellName).button else {
return
}
btn.setImage(UIImage(named: "yourNotSelectedImagename"), for: .normal)
}

Multiple custom cell in TableViewController

Scenario
| First Cell |
| Second Cell |
| SWITCH |
| |
| Third Cell |
| TextField |
I created a dynamic table view with three different classes: SecondTableCell (inside it has the outlet of a switch) and ThirdTableCell (inside it has an outlet of a textField)
The switch is Off.
I need to see textField.isUserInteractionEnabled = false then the switch is turned on.
How can I do this?
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var customTableView: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellSwitch = tableView.dequeueReusableCell(withIdentifier: "cellSwitch")! as! SwitchTableViewCell
let cellText = tableView.dequeueReusableCell(withIdentifier: "cellText")! as! TextFieldTableViewCell
}
class SwitchTableViewCell: UITableViewCell {
#IBOutlet weak var switchOutlet: UISwitch!
#IBAction func switchAction(_ sender: UISwitch) {
if sender.isOn == true{
print("swithOn")
}else{
print("swithOff")
}
}
}
class TextFieldTableViewCell: UITableViewCell {
#IBOutlet weak var textFieldColor: UITextField!
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SwitchDelegate {
#IBOutlet weak var customTableView: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellSwitch = tableView.dequeueReusableCell(withIdentifier: "cellSwitch")! as! SwitchTableViewCell
let cellText = tableView.dequeueReusableCell(withIdentifier: "cellText")! as! TextFieldTableViewCell
cellSwitch.delegate = self
cellText.delegate = self
}
func valueDidChange(isOn: Bool) {
tableView.visibleCells.forEach { cell
if let cell = cell as? TextFieldTableViewCell {
cell.textField.isUserInteractionEnabled = false
}
}
}
}
protocol SwitchDelegate {
func valueDidChange(isOn: Bool)
}
class SwitchTableViewCell: UITableViewCell {
#IBOutlet weak var switchOutlet: UISwitch!
var delegate: SwitchDelegate?
#IBAction func switchAction(_ sender: UISwitch) {
delegate?.valueDidChange(isOn: sender.isOn)
}
}
class TextFieldTableViewCell: UITableViewCell {
#IBOutlet weak var textField: UITextField!
}
When you setup the cells in the tableviewcontroller, you can define at view row you want to use which tableviewcell class. Just like in my below example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if ((indexPath.row < 25 && counter > 25) || (indexPath.row < counter)) {
let cell = tableView.dequeueReusableCell(withIdentifier: "SaleItems", for: indexPath) as! MyTableCellTableViewCell
let TapRecognize = UITapGestureRecognizer(target: self, action: #selector(self.PictureTap(sender:)))
TapRecognize.numberOfTapsRequired = 1
TapRecognize.name = jSonData[indexPath.row]["advid"]
// Configure the cell...
cell.Megnevezes.text=jSonData[indexPath.row]["advdescription"]!
cell.EladasiAr.text=jSonData[indexPath.row]["advprice"]! + " " + jSonData[indexPath.row]["advpricecur"]!
cell.addGestureRecognizer(TapRecognize)
cell.LoadPicture(AdvID: Int(jSonData[indexPath.row]["advid"]!)!)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PagerCell", for: indexPath) as! ChangePageCell
cell.delegate = self
return cell
}
}
In my example the last row of the tableview is different. It is not exactly clear from your explanation what do you really want to do with the switch cell. But you should ensure that you can identify the cells and their classes to know where to pass the action's.
In my case the gestureRecognizer gets a name, which contains a relevant advertisement ID to load the photos, linked to that advertisement details.
When you tap on the cell, it calls the tap recogniser's action and name can be used to identify which cell is touched.

How can I get indexPath.row in cell.swift

I have 2 files.
myTableViewController.swift
myTableCell.swift
Can I get the indexPath.row in myTabelCell.swift function?
Here is myTableCell.swift
import UIKit
import Parse
import ActiveLabel
class myTableCell : UITableViewCell {
//Button
#IBOutlet weak var commentBtn: UIButton!
#IBOutlet weak var likeBtn: UIButton!
#IBOutlet weak var moreBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func likeBtnTapped(_ sender: AnyObject) {
//declare title of button
let title = sender.title(for: UIControlState())
//I want get indexPath.row in here!
}
Here is myTableViewController.swift
class myTableViewController: UITableViewController {
//Default func
override func viewDidLoad() {
super.viewDidLoad()
//automatic row height
tableView.estimatedRowHeight = 450
tableView.rowHeight = UITableViewAutomaticDimension
}
// cell config
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//define cell
let cell = tableView.dequeueReusableCell(withIdentifier: "myTableCell", for: indexPath) as! myTableCell
}
As you can see... I'm trying to get indexPath.row in myTableCell, liktBtnTapped function.
Could you let me know how can I access or get IndexPath.row?
I have created a UIResponder extension with a recursive method that you can use in any UIView (which inherits from UIResponder) to find a parent view of a specific type.
import UIKit
extension UIResponder {
/**
* Returns the next responder in the responder chain cast to the given type, or
* if nil, recurses the chain until the next responder is nil or castable.
*/
func next<U: UIResponder>(of type: U.Type = U.self) -> U? {
return self.next.flatMap({ $0 as? U ?? $0.next() })
}
}
Using this, we can extend UITableViewCell with some convenient read-only computed properties for the table view and index path of the cell.
extension UITableViewCell {
var tableView: UITableView? {
return self.next(of: UITableView.self)
}
var indexPath: IndexPath? {
return self.tableView?.indexPath(for: self)
}
}
Here is how you could use it in your example:
#IBAction func likeBtnTapped(_ sender: AnyObject) {
//declare title of button
let title = sender.title(for: UIControlState())
//I want get indexPath.row in here!
self.indexPath.flatMap { print($0) }
}
Swift 4+
Try this inside your cell.
func getIndexPath() -> IndexPath? {
guard let superView = self.superview as? UITableView else {
print("superview is not a UITableView - getIndexPath")
return nil
}
indexPath = superView.indexPath(for: self)
return indexPath
}
Easy.. You can do like this inside button action:
let section = 0
let row = sender.tag
let indexPath = IndexPath(row: row, section: section)
let cell: myTableCell = self.feedTableView.cellForRow(at: indexPath) as! myTableCell
And afterwards in cellForRowAtIndexPath:
// add the row as the tag
cell.button.tag = indexPath.row
Another Approach for Swift 4.2 and not assuming Superview will be always a tableview
extension UITableViewCell{
var tableView:UITableView?{
return superview as? UITableView
}
var indexPath:IndexPath?{
return tableView?.indexPath(for: self)
}
}
Usage example
#IBAction func checkBoxAction(_ sender: UIButton) {
guard let indexPath = indexPath else { return }
sender.isSelected = !sender.isSelected
myCustomCellDelegate?.checkBoxTableViewCell(didSelectCheckBox: sender.isSelected, for: indexPath)
}
Swift 4.1. Here I created function to get IndexPath. Just pass your UIView(UIButton,UITextField etc) and UITableView object to get IndexPath.
func getIndexPathFor(view: UIView, tableView: UITableView) -> IndexPath? {
let point = tableView.convert(view.bounds.origin, from: view)
let indexPath = tableView.indexPathForRow(at: point)
return indexPath
}
Create a property indexPath in the cell class and set it in cellForRowAtIndexPath when the cell is reused.
But there is a caveat: Some table view methods to rearrange the cells don't call cellForRowAtIndexPath. You have to consider this case.
But if you use always only reloadData() it's safe and pretty easy.
Another way is to put the code regarding controlling things back in the controller class and run it via callback closures capturing the index path.
Heres another way of doing it
import UIKit
import Parse
import ActiveLabel
class myTableCell : UITableViewCell {
//Button
#IBOutlet weak var commentBtn: UIButton!
#IBOutlet weak var likeBtn: UIButton!
#IBOutlet weak var moreBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
}
class myTableViewController: UITableViewController {
//Default func
//assuming you have an array for your table data source
var arrayOfTitles = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//automatic row height
tableView.estimatedRowHeight = 450
tableView.rowHeight = UITableViewAutomaticDimension
}
// cell config
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//define cell
let cell = tableView.dequeueReusableCell(withIdentifier: "myTableCell", for: indexPath) as! myTableCell
cell.commentBtn.tag = indexPath.row
cell.commentBtn.addTarget(self, action: #selector(likeBtnTapped(_:), forControlEvents:.TouchUpInside)
//cell config end
#IBAction func likeBtnTapped(sender: UIButton) {
let btn = sender
let indexP = NSIndexPath(forItem: btn.tag, inSection: 0)
let cell = tableView.dequeueReusableCell(withIdentifier: "myTableCell", for: indexP) as! myTableCell
//I want get indexPath.row in here!
let title = arrayOfTitles[indexP.row]
//declare title of button
cell.commentBtn.setTitle(title, forState: UIControlState.Normal)
}
}
My solution was subclassing UITableViewCell, so can add IndexPath property. assign custom class for table view cell in storyboard. assign IndexPath value when rowAtIndexPath called.
class MyTableViewCell: UITableViewCell {
var indexPath: IndexPath?
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cellid1", for: indexPath)
(cell as? MyTableViewCell)?.indexPath = indexPath
return cell
}
Swift 5:
if
let collectionView = superview as? UICollectionView,
let index = collectionView.indexPath(for: self)
{
// stuff
}