Handle Button Presses in CustomUITableViewCells Without Tags

Press on

Image for post
Image for post
Photo by Mad Fish Digital on Unsplash

Difficulty: Beginner | Easy | Normal | Challenging

Creating a button on every UITableViewCell is something you might want to do (Protip: Don’t use this for traversing to another viewcontroller).

But how do you know which cell has received that button press?

Let us press on…

Prerequisites:

The target

We simply want to have a button that displays a UIAlertController on the screen when a button is pressed.

It’s not a that unusual an App to want to create…

Image for post
Image for post

The simple code

This project has a rather simple CustomTableViewCell with a rather simple layout (but of course the cell identifier needs to be set in the Storyboard — I’ve called my “cell” and referenced that later).

Image for post
Image for post
Image for post
Image for post
Click for Gist

Which is called from the UIViewController called ViewController.

Image for post
Image for post
Click for Gist

Which of course when you run (if you are following along) means there won’t be any visible action when the UIButton is clicked. Follow on…that’s what this article is about!

Solving with a tag (BAD)

One way of solving this it to place a tag on each UIButton instance (of course each UITableViewCell contains a single button on each row!).

This can be set in our ViewController inside tableView(_:cellForRowAt:) with just a couple of lines

cell.alertButton.tag = indexPath.row
cell.alertButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

giving us a modified tableView(_:cellForRowAt:)

Image for post
Image for post
Click for Gist

Which then inevitably calls our @objc function that engages our UIAlertController which in this example is the buttonTapped function as expressed below:

Image for post
Image for post
Click for Gist

This works fine!

BUT:

  • Multiple sections provides a problem
  • You rely on matching Integers which isn’t that great

Solving with delegates (Ok)

By setting up a delegate that conforms to a protocol we can pass information to and from the UITableViewCell. To do so we can set up a ClickDelegate

Image for post
Image for post
Click for Gist

Which the UIViewController ViewController will conform to, and this is where we will call the UIAlertController

Image for post
Image for post
Click for Gist

and of course we will need to set the delegate intableView(_:cellForRowAt:) which is just a single line cell.delegate = self which gives us the following code:

Image for post
Image for post
Click for Gist

Want the full classes? Look at the full Git repo

Solving with closures (Ok)

Rather than using a delegate we can set up a closure pattern, that means when the button is pressed a closure is called in the UIViewController ViewController.

The CustomTableViewCell calls this optional closure

Image for post
Image for post
Click for Gist

which is both set and called in tableView(_:cellForRowAt:), perhaps as you might have expected.

Image for post
Image for post
Click for Gist

Please not that this article isn’t about memory management or weak or unowned self (which are options to deal with this) but please do proceed with care with this solution.

Want the full classes? Look at the full Git repo

Conclusion:

Using the “wrong” method to work out a particular problem using Swift and UIKit can make your project difficult to maintain and extend; if you use tags to indicate which cell is clicked you may well have problems if you wish to use different segments in your UITableView.

This means those people who insist you do something in the right and proper way are, on occasion, right. When you wish to know which UITableViewCell has been clicked you can choose between using a delegate and closures. These patterns are common in iOS and are certainly something you should be familiar with when coding with UIKit.

Want to view the whole project? Look at the full Git repo.

Any questions? Get in touch with me on Twitter and I’ll help you out!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store