Is it wrong to add action to button in tableViewCell with tag?
I have a UItableViewCell with a button inside it, I set the tag of the button and add the action of the button in my ViewController using the tag.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BillHistoryTableViewCell", for: indexPath) as! BillHistoryTableViewCell
let cellData = billHistories[indexPath.row]
cell.setup(with: cellData)
cell.retryButton.tag = indexPath.row
return cell
}
@IBAction func billHistoryRetryButtonDidTap(_ sender: UIButton) {
let index = sender.tag
if let id = billHistories[index].transactionInfo?.billUniqueID {
hidePayIdGeneralTextField()
billIdTextField.text = id.toNormalNumber()
inquiryGeneralBillRequest()
}
}
I want to know is it wrong for any reason? someone told me it is not good because it uses lots of memory to use tags.
1 answer
-
answered 2022-01-19 21:41
Maor Atlas
Will it work? yes, but as mentioned above, this is not the best approach, I'd avoid using tags unless this is just for some POC. There are better approaches to handle it. The first I'd suggest is using delegation to inform back to the controller, here's an example:
class BillHistoryTableViewController { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "BillHistoryTableViewCell", for: indexPath) as! BillHistoryTableViewCell let cellData = billHistories[indexPath.row] cell.setup(with: cellData) cell.index = indexPath.row cell.delegate = self return cell } } extension BillHistoryTableViewController: BillHistoryTableViewCellDelegate { func didTapButton(index: Int) { print("tapped cell with index:\(index)") if let id = billHistories[index].transactionInfo?.billUniqueID { hidePayIdGeneralTextField() billIdTextField.text = id.toNormalNumber() inquiryGeneralBillRequest() } } } protocol BillHistoryTableViewCellDelegate: AnyObject { func didTapButton(index: Int) } class BillHistoryTableViewCell: UITableViewCell { weak var delegate: BillHistoryTableViewCellDelegate? var cellData: CellData? var index: Int? func setup(with cellData: CellData) { self.cellData = cellData } @IBAction func buttonPressed(_ sender: UIButton) { guard let index = index else { return } delegate?.didTapButton(index: index) } }
Another approach that I prefer lately is using Combine's PassThroughSubject, it requires less wiring and delegate definitions.
import Combine class BillHistoryTableViewController { var cancellable: AnyCancellable? func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "BillHistoryTableViewCell", for: indexPath) as! BillHistoryTableViewCell let cellData = billHistories[indexPath.row] cell.setup(with: cellData) cell.index = indexPath.row cancellable = cell.tappedButtonSubject.sink { [weak self] index in guard let self = self else { return } print("tapped cell with index:\(index)") if let id = self.billHistories[index].transactionInfo?.billUniqueID { self.hidePayIdGeneralTextField() self.billIdTextField.text = id.toNormalNumber() self.inquiryGeneralBillRequest() } } return cell } } class BillHistoryTableViewCell: UITableViewCell { var tappedButtonSubject = PassthroughSubject<Int, Never>() var cellData: CellData? var index: Int? func setup(with cellData: CellData) { self.cellData = cellData } @IBAction func buttonPressed(_ sender: UIButton) { guard let index = index else { return } tappedButtonSubject.send(index) } }
You can make it even shorter by injecting the index with the cellData, e.g:
func setup(with cellData: CellData, index: Int) { self.cellData = cellData self.index = index }
but from what I see in your example, you don't even need the index, you just need the CellData, so if we'll take the Combine examples these are the main small changes you'll have to make:
var tappedButtonSubject = PassthroughSubject<CellData, Never>() tappedButtonSubject.send(cellData)
and observing it by:
cancellable = cell.tappedButtonSubject.sink { [weak self] cellData in if let id = cellData.transactionInfo?.billUniqueID { // } }
do you know?
how many words do you know