Skip to content

DDD 4.10. Displaying a Refresh Control for Table Views

rayastar edited this page Feb 14, 2015 · 1 revision

Problem

You want to display a nice refresh UI control on top of your table views that allows your users to intuitively pull down the table view in order to update its contents.

Solution

Simply create a table view controller (as discussed in Recipe 4.9) and set its refresh Control property to a new instance of UIRefreshControl class, as shown here:

- (id)initWithStyle:(UITableViewStyle)style{
    self = [super initWithStyle:style];
    if (self) {

        [self.tableView registerClass:[UITableViewCell class]
               forCellReuseIdentifier:CellIdentifier];

        self.allTimes = [NSMutableArray arrayWithObject:[NSDate date]];

        /* Create the refresh control */
        self.refreshControl = [[UIRefreshControl alloc] init];
        self.refreshControl = self.refreshControl;
        [self.refreshControl addTarget:self
                                action:@selector(handleRefresh:)
                      forControlEvents:UIControlEventValueChanged];

    }
    return self;
}

Create a new instance of this class simply by calling its init method. Once you are done, add this instance to your table view controller, as described in the Solution section of this recipe. Now you’ll want to know when the user has triggered a refresh on your table view. To do this, simply call the addTarget:action:forControlEvents: instance method of your refresh control and pass the target object and a selector on that object that takes care of the refresh for you. Pass UIControlEventValueChanged to the forControlE vents parameter of this method.

So let’s start in the implementation file of our table view controller and define our refresh control and our data source:

#import "ViewController.h"

static NSString *CellIdentifier = @"Cell";

@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *allTimes;
@property (nonatomic, strong) UIRefreshControl *refreshControl;
@end

The allTimes property is a simple mutable array that will contain all the instances of NSDate in it as the user refreshes the table view. We have already seen the initialization of our table view controller in the Solution section of this recipe, so I won’t write it again here. But as you saw there, we have hooked the UIControlEventValueChanged event of our refresh control to a method called handleRefresh:. In this method, all we are going to do is add the current date and time to our array of dates and times and then refresh the table view:

- (void) handleRefresh:(id)paramSender{

    /* Put a bit of delay between when the refresh control is released
     and when we actually do the refreshing to make the UI look a bit
     smoother than just doing the update without the animation */
    int64_t delayInSeconds = 1.0f;
    dispatch_time_t popTime =
        dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

        /* Add the current date to the list of dates that we have
         so that when the table view is refreshed, a new item will appear
         on the screen so that the user will see the difference between
         the before and the after of the refresh */
        [self.allTimes addObject:[NSDate date]];

        [self.refreshControl endRefreshing];

        NSIndexPath *indexPathOfNewRow =
            [NSIndexPath indexPathForRow:self.allTimes.count-1 inSection:0];

        [self.tableView
             insertRowsAtIndexPaths:@[indexPathOfNewRow]
             withRowAnimation:UITableViewRowAnimationAutomatic];
    });

}

Last but not least, we will provide the date to our table view through the table view’s delegate and data source methods:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section{
    return self.allTimes.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath{


    UITableViewCell *cell = [tableView
                             dequeueReusableCellWithIdentifier:CellIdentifier
                             forIndexPath:indexPath];

    cell.textLabel.text = [NSString stringWithFormat:@"%@",
                           self.allTimes[indexPath.row]];

    return cell;
}
Clone this wiki locally