27

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.

5 Answers 5

85

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!

Sign up to request clarification or add additional context in comments.

5 Comments

thanks a lot. its worked for me. If I want to send someting from SepetCell to tableView what should I do? For example, I have a strepper and when I click on it I want to change the label's value
ok I found it by some try:) I made some changes on the code like: var onFavButtonTapped : ((Int) -> Void)? = nil **** if let onButtonTapped = self.onButtonTapped { onButtonTapped(3) } **** cell!.onButtonTapped = {(x: Int) in println(x) }
great to hear!. BTW, if you found my answer useful, please consider upvoting :)
yeah i already tried to do it but because of I'm new user, system is not allowing me to do it. It wants at least 15 reputation. Sorry :) When I have 15 rep I will do it :)
this is probably one of the most beautiful solutions i've seen since i've started writing in swift. thank you for writing it!
1

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)

}

Comments

1
extension ViewController: UITableViewDelegate, UITableViewDataSource {

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell = UITableViewCell()
    
    //cell.buttonPressed add in Your tableViewCell file
    
    cell.buttonPressed = { [self] in
        print("Cell")
    }
}

add this in your cell file

  var buttonPressed : (() -> ()) = {}


   @IBAction func btnclick(_ sender: Any) {
        buttonPressed()
    }

Comments

0

Add target for that button.

button.addTarget(self, action: #selector(connected(sender:)), for: .touchUpInside)

Set tag of that button since you are using it.

button.tag = indexPath.row

Achieve this by subclassing UITableViewCell. button on that cell, connect it via outlet.

To get the tag in the connected function:

@objc func connected(sender: UIButton){
    let buttonTag = sender.tag
}

Comments

-2

2 am answer: You're over thinking this. Create a custom TableViewCell class; set the prototype cell class to your new custom class; and then create an IBAction.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.