iOS

iOS Programming 101: Implementing Pull-to-Refresh and Handling Empty Table


In this iOS Programming 101 post, I would like to answer two common questions raised by our readers.

  1. I follow your table view tutorial to create my first app. The tutorial is great. It shows us how to display data in the table view. But what if the table is empty? When there is no data, the app should display a friendly message instead of just display empty rows. How can I do that?
  2. I like the pull-to-refresh gesture. It’s a great way for content update. How can I implement such feature in my table-based app?

Let us first take a look at the first question and see how to display a text message when the table is empty. The UITableView class includes the backgroundView property, which is the background view of the table view. This property is set to nil by default. To display a message or an image when the table is empty, usually we configure this property and set it to our own view.

uirefreshcontrol featured

Displaying Message in Empty Table

There is no better way to illustrate the usage by an example. You can first download the sample project from here. The demo app uses a free web-based API from Kiva.org to retrieve the most recent fundraising loans and display the loan information in a table view. If you haven’t heard of Kiva.org, it is a non-profit organization with a mission to connect people through lending to alleviate poverty. It lets individuals lend as little as $25 to help create opportunity around the world. Kiva provides free web-based APIs for developers to access their loan data.

If you compile and run the demo app now, it shows a blank table. Let’s modify the app and display a friendlier message. In the KivaLoanTableViewController.m, update the numberOfSectionsInTableView: method with the following code:

When there is no data available (i.e. the loans object is nil), we create a UILabel and set it as the backgroundView property to display the “No data is currently available. Please pull down to refresh.” message.

Empty UITableView with Text Message

Easy, right? Now that you should have a basic understanding of the backgroundView property. Let’s continue to look into the pull-to-refresh feature.

Implementing Pull-to-Refresh in UITableView

The pull-to-refresh interaction for updating data of a table view was originally created by Loren Brichter. Since its invention, an endless number of apps including Apple’s Mail app adopt the design for content updates. Prior to iOS 6, adding such feature to your app is not an easy task. You either implement your own solution or rely on third-party libraries. Both solutions will take you considerable time and efforts. Thanks to the popularity of the pull-to-refresh feature. Starting from iOS 6.0, Apple added a pull-to-refresh control known as UIRefreshControl in iOS SDK. With the built-in control, you just need to write a few lines of code to add the pull-to-refresh feature in your app.

The UIRefreshControl is a standard control that provides the pull-to-refresh feature. You can simply link a refresh control with a table view controller. The controller then automatically adds the control to the table and manage the display of that control in response to the appropriate gestures.

In the viewDidLoad: method of KivaLoanTableViewController.m, add the following code:

It is very simple to use UIRefreshControl. Simply instantiate it and assign it to the table view controller’s refreshControl property. That’s it. The table view controller handles the work of adding the control to the table’s visual appearance.

Optionally, you can change the background color and tint color by using the backgroundColor and tintColor properties respectively.

The refresh control doesn’t initiate the refresh operation when it is first created. Instead, when the table view is pulled down sufficiently, the refresh control triggers the UIControlEventValueChanged event. We have to assign an action method to this event and use it to perform the retrieval of the latest loans (that is, calling the getLatestLoans: method).

If you compile and run the app, the pull-to-refresh feature should work. Try to pull down the table until it triggers the refresh. But there is a problem. The refresh control still appears even after the table content is loaded.

So how can we hide the refresh control?

It’s your responsibility to hide the refresh control. The control itself doesn’t know when it should be hidden. To hide the control, you can simply call the endRefreshing: method:

The UIRefreshControl provides an option for you to assign a title text via the attributedTitle property. In the demo app, we’ll display the date/time of the last refresh operation in the refresh control. Obviously, we need to modify the reloadData: method in the demo app as we want to update the last update date/time and hide the refresh control when the data is loaded in the table. So, update the method with the following code:

The code is very straightforward. We determine the current date/time and create the corresponding attributedTitle. Lastly, we hide the control by calling the endRefreshing: method.

Now it’s ready to test the app again. Your app should work properly. The refresh control should be hidden right after content update.

uirefreshcontrol demo

Cool, right? So far the app works really well for normal situation. What if your app fails to connect to the Internet? The refresh control won’t disappear. You’ll need to insert a few lines of code to handle that exception. I’ll leave it for you as an exercise.

What do you think about this tutorial? Feel free to leave comment and share your thought.

Love this tutorial? You will probably want to check out our Intermediate Swift Book.

iOS
How to Use iOS Charts API to Create Beautiful Charts in Swift
iOS
Creating a Custom Keyboard Using iOS 8 App Extension
iOS
Building a Message Sticker App Extension in Xcode 8
  • ohdowload

    ohdowloadohdowload

    Author Reply

    i got a problem when i did pull to refresh to get the data from wordpress/blog, it doesn’t fetch a new content for me even there is new updated content. But it’s working well with JSON API from twitter feed or KIVA feed.


  • koteswar

    koteswarkoteswar

    Author Reply

    Good Work


  • ohdowload

    ohdowloadohdowload

    Author Reply

    pleasee give the solution for exercise. i stuck for hours now.


    • Alex

      AlexAlex

      Author Reply

      Same here, hope someone can share something. Great guide thou.


      • Simon Ng

        Simon NgSimon Ng

        Author Reply

        One hint is to modify the code in the getLatestLoans method. This method is responsible for getting the data from Kiva.org. You need to add an “else” block for handling the exception.


        • PH

          PHPH

          Author Reply

          Why didn’t you include that in the tutorial? I get the idea for making the students copy and paste the code in but your tutorial is incomplete.


  • Regi Ellis

    Regi EllisRegi Ellis

    Author Reply

    Protocols were not attached in the KivaLoanTableViewController.h file, yet the required methods were implemented. Is the protocols optional if you know the methods you intend to use or inherit?


  • Boomslam

    BoomslamBoomslam

    Author Reply

    That’s great direction to learn, thank you.
    but in case of the app cannot connect to the internet how can i handle this exception?, what’s lesson will you suggest to learn more?
    I’m just new to iOS development.


    • Simon Ng

      Simon NgSimon Ng

      Author Reply

      One hint is to modify the code in the getLatestLoans method. This method is responsible for getting the data from Kiva.org.


  • tomqz

    tomqztomqz

    Author Reply

    Hi! Great tutorial, but there is a small problem. In Your example if there are only one or two rows with data, UITableView will display them correctly and also will display the message “No data…”. Is there away to fix this?


    • Ardi Al Haidar

      just set nil to background view of table view. you can do that in “tableView: numberOfRowsInSection” method.

      if (loans) {
      self.tableView.backgroundView = nil;


      } else {

      }


  • John

    JohnJohn

    Author Reply

    can this method can be use on the RSS Feed source code (of appcoda)?


  • Trung Dinh

    Trung DinhTrung Dinh

    Author Reply

    I need to handle the event “ViewTable has been successfully loaded”, i.e., I need to know whether the table has been loaded or not. What should I do for such kind of scenario ? Thank you in advanced.


  • pentool

    pentoolpentool

    Author Reply

    Thank you, great tut!


  • Chad Wilken

    Great article, cheers


  • David Richards

    Thank you very much for the article. This is a great solution


  • Franz Grabner

    But you can’t have both: Empty message and Pull-to-refresh. It’s either or. Or how do you solved this?


  • Stunning Guy

    Thanks for your excellent tutorials. I wonder why the iOS Programming 101 Series do not come with the full source code for quick reference.


  • Vaibhav Saran

    And for a UITableView inside UIViewController, you have to add refreshControl as a subview of UITableView

    I never thought it would be so simple. 🙂


  • Amol Nikam

    Amol NikamAmol Nikam

    Author Reply

    Thank you….I was thinking that it is very difficult but but you helped me thank you….


  • Akira Shimosoeda

    Pretty cool stuff. I have an issue with the messageLabel not dissapearing from view when reloaded. Dunno why.


  • Supriya Pathari

    In collection view, if we have around 6 cells visible in a View it works great. But if we have 1 cell I can see title on top of the collection view after pull to refresh.


    • Ranjeet Singh

      when you have data available hide the UIlabel because you might not be using reusable cell or there could be any other reason depending upon your code .
      but it will work for you
      cheers.


  • ic_R@j

    ic_R@jic_R@j

    Author Reply

    anyone working with Photo editor Extension in Objective C??


  • Barry

    BarryBarry

    Author Reply

    Hello,

    I am trying to display a message in an empty table, but i am using fetchresultcontoller and i thought i could use the messagelabel in numberOfRowsInSection. It seems to work but i can see “row lines” and not a blank background. How can i achieve a blank background?

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    let numberOfRowInSection = frc.sections?[section].numberOfObjects
    if numberOfRowInSection > 0 {
    return numberOfRowInSection!
    } else {
    // Display a message when the table is empty
    let messageLabel = UILabel(frame: CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height))

    messageLabel.text = “Nog geen bonnen ingevoerd.”;
    messageLabel.textColor = UIColor.blackColor();
    messageLabel.numberOfLines = 0;
    messageLabel.textAlignment = NSTextAlignment.Center;
    messageLabel.font = UIFont(name: “Palatino-Italic”, size: CGFloat(22))

    self.tableView.backgroundView = messageLabel;

    }


  • Chathura Lakmal

    Awesome


  • Андрей Шевцов

    concise and straightforward. awesome)


Shares