4
votes

I have a UITableViewController in my app with a UIRefreshControl added to it. Sometimes however (I'm not sure how to reproduce this, it happens every now and then), I get some extra whitespace at the top of the table view with the refresh control being offset even below that.

This is what it looks like (idle on the left, being pulled down on the right):

screenshot

I don't have any clue what could be causing this. In my viewdidload I'm only instantiating the refresh control and calling an update function that sets the attributed title. I've moved adding the refresh control to the table view into the viewDidAppear as I've read elsewhere. This is what that code looks like:

override func viewDidLoad() {
    super.viewDidLoad()
    self.refreshControl = UIRefreshControl()

    updateData()
}

override func viewDidAppear(animated: Bool) {
    refreshControl!.addTarget(self, action: "updateData", forControlEvents: UIControlEvents.ValueChanged)
    tableView.insertSubview(self.refreshControl!, atIndex: 0)
}

func updateData() {
    //...
    ServerController.sendParkinglotDataRequest() {
        (sections, plotList, updateError) in
        //...

        // Reload the tableView on the main thread, otherwise it will only update once the user interacts with it
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.tableView.reloadData()

            // Update the displayed "Last update: " time in the UIRefreshControl
            let formatter = NSDateFormatter()
            formatter.dateFormat = "dd.MM. HH:mm"
            let updateString = NSLocalizedString("LAST_UPDATE", comment: "Last update:")
            let title = "\(updateString) \(formatter.stringFromDate(NSDate()))"
            let attributedTitle = NSAttributedString(string: title, attributes: nil)
            self.refreshControl!.attributedTitle = attributedTitle
        })
    }
}
2
Have you tried to remove the uirefreshcontrol and test whether the problem persists? How does your view hierarchy look like? Do you have other subviews in your view controller's view which are below your table view? - croX
There are no further views below the tableview, it's just the navigation bar and tableview and the tableview cells. Besides the refresh control they're all configured in the storyboard. I'm going to remove the refresh control and see if the problem persists, but it's rather hard to debug as this issue only occurs rarely. - Kilian
Oh wait, that line "tableView.insertSubview"... I have that from before I moved to using a UITableViewController and read that UIRefreshControl shouldn't be used like that in normal UITableViews. That sure isn't needed in this case, could that be the issue? - Kilian

2 Answers

3
votes

Do you need to add the refresh control as a subview of the tableView? I think all you need to do is assign self.refreshControl. According to the documentation:

The default value of this property is nil.

Assigning a refresh control to this property adds the control to the view controller’s associated interface. You do not need to set the frame of the refresh control before associating it with the view controller. The view controller updates the control’s height and width and sets its position appropriately.

Adding a subview in viewDidAppear could get executed more than once. If you push a controller from a cell and pop back this will get called again. It could be that insertSubview checks if the refresh already has a parent and removes it first, so might not be your issue. You should only do the insert when the controller appears for the first time.

updateData could also be getting added multiple times.

So I think you only need to assign self.refreshControl and then add a handler for the refresh action as you do now using addTarget but this time do it on self.refreshControl.

You can also do all this from storyboard. In storyboard you select the UITableViewController and on the attribute inspector simply set the Refreshing attribute to enabled. This adds a UIRefreshControl into the table and you can see it on the view hierarchy. You can then simply CTRL drag as normal from the refresh control into the .h file and add an action for valueChange which will be fired when you pull down on the refresh control in the table.

0
votes

Well, I believe that your described behavior might not necessarily be caused by the refresh control. According to the fact that you don't have any other subviews below your table view I would recommend you to try to place a "fake"-view below your table view. I usually prefer an empty label with 0 side length.

enter image description here

I had similar issues like yours where my table view insets were broken in some cases. And as soon as I used this "fake" subview the problems disappeared. I've read about this issue in some other threads, too. And the solution was this. Seems to be an odd behavior/bug.

Give it a try :)