Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a button with click event on UITableViewCell in Swift?

In my main page, I created a xib file for UITableViewCell. I'm loading the cell from that xib file and its working fine.

Inside of the cell I have some labels and buttons. I'm aiming to change the label by clicking to the button on the cell.

My Code likes below

import UIKit


class SepetCell: UITableViewCell{

    @IBOutlet var barcode: UILabel!
    @IBOutlet var name: UILabel!
    @IBOutlet var fav: UIButton!
    @IBOutlet var strep: UIStepper!
    @IBOutlet var times: UILabel!



    @IBAction func favoriteClicked(sender: UIButton) {
        println(sender.tag)
        println(times.text)

        SepetViewController().favorite(sender.tag)



    }
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
}

This is my xib files behind codes as .swift.

The codes in the main page likes below:

  import UIKit
import CoreData

class SepetViewController: UIViewController, UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate {

  @
  IBOutlet
  var sepetTable: UITableView!
    var barcodes: [CART] = []

  let managedObjectContext = (UIApplication.sharedApplication().delegate as!AppDelegate).managedObjectContext

  override func viewWillAppear(animated: Bool) {
    if let moc = self.managedObjectContext {


      var nib = UINib(nibName: "SepetTableCell", bundle: nil)
      self.sepetTable.registerNib(nib, forCellReuseIdentifier: "productCell")
    }
    fetchLog()
    sepetTable.reloadData()
  }

  func fetchLog() {

    if let moc = self.managedObjectContext {
      barcodes = CART.getElements(moc);
    }
  }



  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) - > Int {
    return self.barcodes.count
  }

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - > UITableViewCell {


    let cell = tableView.dequeueReusableCellWithIdentifier("productCell") as ? SepetCell


    if cell == nil {
      println("cell nil")

    }



    let product: CART
    product = barcodes[indexPath.row]



    cell!.barcode ? .text = product.barcode
    cell!.name ? .text = product.name
    cell!.fav.tag = indexPath.row

    return cell!
  }

  func favorite(tag: Int) {



  }
}

When i clicked fav button inside of the Cell. I wanted to change times label text to anything for example.

When I clicked to the fav button, the event will gone to the SepetCell.swift favoriteClicked(sender: UIButton) function.

So if i try to call: SepetViewController().favorite(sender.tag)

It will go inside of the

func favorite(tag: Int) {

      sepetTable.reloadData()

    }

but sepetTable is nil when it is gone there. I think it is because of when I call this SepetViewController().favorite(sender.tag) function. It firstly creates SepetViewController class. So because of object is not setted it is getting null.

How can I reach that sepetTable or what is the best way to solve this issue.

Thanks.

like image 490
Kemal Müderrisoğlu Avatar asked May 07 '15 15:05

Kemal Müderrisoğlu


People also ask

How do you handle button clicks in Swift?

Then we should create a swift button action process method ( func onClick(sender: UIButton!) ) to handle the button on-click event. Call the UIButton object's addTarget method to connect the button with the onClick event. This line of code should be placed inside the above viewDidLoad method.

How do you get the indexPath row when a button in a cell is tapped?

add an 'indexPath` property to the custom table cell. initialize it in cellForRowAtIndexPath. move the tap handler from the view controller to the cell implementation. use the delegation pattern to notify the view controller about the tap event, passing the index path.


2 Answers

Popular patterns for solving this problem are closures and delegates. If you want to use closures, you would do something like this:

final class MyCell: UITableViewCell {     var actionBlock: (() -> Void)? = nil 

then

    @IBAction func didTapButton(sender: UIButton) {         actionBlock?()     } 

then in your tableview delegate:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - > UITableViewCell {      let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier") as? MyCell     cell?.actionBlock = {        //Do whatever you want to do when the button is tapped here     } 

A popular alternative is to use the delegate pattern:

    protocol MyCellDelegate: class {         func didTapButtonInCell(_ cell: MyCell)     }      final class MyCell: UITableViewCell {         weak var delegate: MyCellDelegate? 

then

    @IBAction func didTapButton(sender: UIButton) {         delegate?.didTapButtonInCell(self)     } 

.. Now in your view controller:

then in your tableview delegate:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - > UITableViewCell {      let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier") as? MyCell     cell?.delegate = self 

And add conformance to the protocol like this:

extension MyViewController: MyCellDelegate {     didTapButtonInCell(_ cell: MyCell) {        //Do whatever you want to do when the button is tapped here     } } 

Hope this helps!

like image 72
raf Avatar answered Oct 17 '22 00:10

raf


All patterns above are fine. my two cents, in case You add by code (for example multiple different cells and so on..) there is a FAR simple solution.

As buttons allow to specify a "target" You can pass directly the controller AND action to cell/button when setting it.

In controller:

let selector = #selector(self.myBtnAction)
setupCellWith(target: self, selector: selector)

...

in custom cell with button:

final func setupCellWith(target: Any? selector: Selector){
       btn.addTarget(target, 
        action: selector,
       for: .touchUpInside)

}
like image 29
ingconti Avatar answered Oct 16 '22 23:10

ingconti