Your First Table View (III): Cell Actions and Pull To Refresh

  • home
  • /
  • Your First Table View (III): Cell Actions and Pull To Refresh

Digital Leaves. Your First Table View (UITableView). Learn Swift and iOS Programming, easy and fun. Custom Cells. Cell Actions and Pull To Refresh.Welcome back! This is the third and last episode of “Your First Table View”, where we will learn about cell actions and Pull To Refresh. In the previous episodes, we learned from the basics of UITableView, Index Paths, Data Sources and Delegates, to how to create custom cells and allow our users to select then to transition to new view controllers. You might want to read them first if you have never worked with table views in iOS.

What We Are Going To Learn

Users of iOS devices have lots of expectations when it comes to the user interface of their apps. They have gown used not only to certain level of quality, but to some common gestures and interactions. For this reason, it’s important to polish the details when building the most well-known controls like table views.

By and large, actions on cells when you swipe right to left have become a de-facto standard. Initially, that interaction was limited to deleting the item represented by that cell.

However, nowadays you can expect to find any relevant action that makes sense for the items of the table there. As a result, we’ll devote some time to learn how to add that to our user interfaces.

Additionally, after being popularized by the Tweetie application, later acquired by Twitter to become its official app, “Pull to Refresh” has become also a de-facto standard in many apps.

You know how it works, so do your users. You just pull from the top of the table and a spinning wheel appears. Then the contents of the table refresh and the spinning wheel disappears. Your users certainly expect you to add that interaction to your app. Thus, we are going to learn how to correctly implement it.

Adding Actions To Cells

The edition of cells and items in a table view is controller by the Delegate. We only need to add two methods to allow this functionality.

First, we will change the “animals” array from a let property to a var one, to allow changes. Then, we add a tableView:canEditRowAt: method to our view controller. This method indicates if certain row should be editable. In our case, we will return always true, as we want our whole table to be editable.

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
   return true

Next, we will implement another method from the Delegate: tableView:editActionsForRowAt:. Here’s where the real magic happens. In this method, we need to define the actions that we will enable for our cells and return them as an array of UITableViewRowAction.

About UITableViewRowAction

An UITableViewRowAction is nothing more than the definition of an action. It has a name, a style and a block with code to execute if the user triggers the action. The name is the title that we will show in the button for that action. The style affects the appearance of the button. Possible values are .default, .normal and .destructive. Generally speaking, you can use .normal for any non-destructive action, and leave .destructive for deletions and similar operations.

Your First Table View. Pull To Refresh, Cell Actions. Digital Leaves. Learn Swift and Start Building Awesome Apps.The block is where you specify the code to run if the action gets triggered. At the end of the action, you should remember to call setEditing(false, animated: true) in the table view to “dismiss” the swipe.

Thus, without further ado, let’s define some actions for our table view.

We will add two actions:

  • Kill“: this will be a destructive action (obviously), that will delete the animal. This is the equivalent of adding a “Delete” action.
  • Feed“: in contrast, selecting “Feed” will make the animal eat another one. Even thought this is also a destructive action, we will set it as a “normal” style action.

Killing the animal is as easy as removing the selected indexPath.row from the array of animals and updating the table visually. Conversely, in order to feed an animal (the “predator”), we will need to calculate a random index in the array of animals. The chosen index will be the “prey”. We will remove that prey, update the table visually, and issue a message dialog indicating that the predator ate the prey.

The Fancy Way Of Altering A Table View

Thus, let’s start by defining a method for removing an animal from our table and update the table view accordingly. We’ll call this method removeAnimalAtIndex:

func removeAnimalAtIndex(index: Int) {
   // remove the animal in the model.
   animals.remove(at: index)
   // fancy animation to delete the row
   tableView.deleteRows(at: [IndexPath(row: index, section: 0)], with: .automatic)

First, we remove the animal in the array, i.e: the element from the model. Then, we will update the table visually. Usually, for reloading the data of a table view, you use the method tableView.reloadData(). However, it’s always a good idea to perform a fancy update animation when deleting rows via a swipe action in the cell. Luckily, there’s a predefined set of methods we can use to do that, like deleteRows:with: or insertRows:at:.

In order to perform these modifications, we need to wrap all of our operations between two enclosing methods: beginUpdates() and endUpdates().

// ... insert and/or delete rows ...

However, it’s important to realize that once you invoke beginUpdates on a table, you should perform a substantial modification before calling endUpdates. This means that you have to at least insert or delete a row, make a substantial change. If not, you will trigger an exception.

Defining Our Edit Actions

Finally then, let’s define the method tableView:editActionsForRowAt:, incorporating our two actions:

 func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
   let deleteAction = UITableViewRowAction(style: .destructive, title: "Kill") { (action, indexPath) in
      self.removeAnimalAtIndex(index: indexPath.row)
      // "close" the swipe (1)
      self.tableView.setEditing(false, animated: true)
   let feedAction = UITableViewRowAction(style: .normal, title: "Feed") { (action, indexPath) in
      if self.animals.count < 2 { // Do nothing if there's only one animal (2)
         self.showAlertMessage(message: "Nobody else here to eat 😐")
      } else {
         // the predator is our selected cell, look for a prey (3)
         var predator = self.animals[indexPath.row]
         let preyIndex = Int(arc4random_uniform(UInt32(self.animals.count)))
         let prey = self.animals[preyIndex]
         // remove the prey and show message (4)
         self.showAlertMessage(message: "Yum! Yum! The \(predator) ate the \(prey)", afterDismissal: { _ in
            self.removeAnimalAtIndex(index: preyIndex)
      // "close" the swipe (5)
      self.tableView.setEditing(false, animated: true)
   return [deleteAction, feedAction]

First, we define our delete action. We just have to call our removeAnimalAtIndex: method and close the swipe (1).

Next, we define our feed action. In (2), we make sure that there are at least two animals, and if that’s the case, we proceed to defining a predator and a prey (3). The predator is the animal that’s been selected, and we can access it simply with the indexPath.row. Conversely, we will get a random number from 0 to the end of the array (length – 1) by calling arc4random_uniform. This will allow us to get a random animal from the array. Then we will use the method showAlertMessage to show a funny message to the user (4). This method allows you to specify a block to perform after the user dismisses the alert, so we will use it to remove the animal and show the animation.

Finally, we need to “close” the swipe (5).

Yum! Yum! The Mouse Ate The Lion! 😱

This is the definition of the showAlertMessage method:

func showAlertMessage(message: String, afterDismissal: ((Void) -> Void)? = nil) {
   let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
   alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
   self.present(alert, animated: true, completion: nil)

As shown above, the result is a very rich experience for the items in our table view.

Pull To Refresh

Your First Table View. Pull To Refresh, Cell Actions. Digital Leaves. Learn Swift and Start Building Awesome Apps.Next, we are going to add the “Pull to Refresh” functionality to our table view. I consider myself an animal lover, so I don’t like the idea of the table becoming empty because all animals were killed or eaten. It just doesn’t feel right.

Thus, we will reset the array of animals and, consequently, the table view, to its original state upon a “Pull to Refresh”.

Configuring our “Pull To Refresh” control

Actually, adding a “Pull to Refresh” is really easy thanks to another UIKit control: UIRefreshControl. All we need to do to initialize it is defining a property in our view controller of type UIRefreshControl.

Then, in viewDidLoad, we set a title (actually, an attributed string) for the control, and define a target action for its .valueChanged event. Finally, we add the control as a subview at the table view:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
   let pullToRefresh = UIRefreshControl()

   func viewDidLoad() {
      // add pull to refresh
      pullToRefresh.attributedTitle = NSAttributedString(string: "Pull to bring all animals back!")
      pullToRefresh.addTarget(self, action: #selector(ViewController.resetAnimals), for: .valueChanged)

Refreshing The Table View And Dismissing The Control

Next, we need to define the “resetAnimals” method that will be invoked when we do the pull to refresh. In order to reset the animals array without duplicating code, we will define an “allAnimals” array with the original list and will set our animals property at viewDidLoad. In the same way, we will reset our animals array to the contents of the “allAnimals” array again when “resetAnimals” is called.

private let allAnimals = ["dog", "cat", "tiger", "lion", "giraffe", "cow", "horse", "fox", "panda", "bear", "mouse", "pig", "rhinoceros", "hippopotamus", "rabbit", "elephant", "crocodile", "bird", "sheep", "gorilla"]

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
   var animals = allAnimals

   func resetAnimals() {
      self.animals = allAnimals


Notice how we call endRefreshing() at the end. You need to remember to call this function when you have finished updating the table, or the “Pull to Refresh” control will stay at its top.

In conclusion, these are the only steps needed to add the “Pull to Refresh” functionality. Run the application and kill or feed some animals. Then, pull from the top of the screen. The table will reset and all the animals will be back.

Where To Go From Here

All in all, in this episode we learned how to add cell actions like “delete” to our table. We also learned how to add “Pull to refresh” to our table too. These kind of polishing details really add that extra punch to our apps that make them feel professional applications. Besides, users are accustomed to find them in any iOS application, so it’s always a good idea to implement them.

As usual, you can download the whole source code in my Github Repository. If you enjoyed this tutorial, don’t forget to share it on Twitter or Facebook!

If you want to explore how to make your table views look awesome, I recommend you to read my tutorial “Flawless Table Views and Collection Views”. There, I speak about dynamic sizing for your cells and lazy load of images in the context of tables and collections.

However, if you want to know more about other controls, I recommend you “Your First Collection View” series of tutorials.