2

This is my code:

func pullToRefresh() {
    if Reachability().connectionStatus() == .Online {
        self.homewebview.reload()
    } else {
        self.refreshControl.endRefreshing()
        let alert = UIAlertView(title: "No Internet connection", message: "Please check your Internet connection.", delegate: nil, cancelButtonTitle: "Okay")
        alert.show()
    }
}

When internet connection is not available and the user pulls to refresh an alert should be shown and the animation should stop. That works great on iOS 9. But on iOS 10 Beta 2 the animation doesn't disappear. The user have to pull up to make it disappear. It that an iOS 10 bug or am I doing something wrong?

P.S. I already tried to add assert(NSThread.isMainThread()) but that didn't help.

4 Answers4

4

I've just encountered this issue and for those using UIAlertController, you may wish to try something similar to the following:

[self presentViewController:alert animated:TRUE completion:^{
    [self.refreshControl endRefreshing];
}];

This enables the loading spinner to disappear in the background as soon as the alert has been displayed.


Swift Equivalent:

present(alert, animated: true) {
    self.refreshControl.endRefreshing()
}
Matt Carr
  • 413
  • 5
  • 15
3

I also met the same issue. Just work around: please change like below

    let alert = UIAlertView(title: "No Internet connection", message: "Please check your Internet connection.", delegate: nil, cancelButtonTitle: "Okay")
    alert.show()
    self.refreshControl.endRefreshing()

I search in Google and some guys talk about interfere when showing other view but not know the root cause

Tam
  • 94
  • 1
  • 8
3

I think when we are presenting the UIAlertController at the same time refreshController is trying to stop itself. That is why it is not getting time to stop refreshing and stays sometimes. So in my case I put endRefreshing code after 1 second and its working smooth now.

Here is the code which I have used:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    self.refreshControl.endRefreshing()
                }
Manab Kumar Mal
  • 20,788
  • 5
  • 31
  • 43
1

It had similar issues and solved it this way. I have a function to handle all fails (no connectivity, api errors) which is called as a notification, but I will simplify it here.

First I am calling endRefreshing asynchronously (try without, you should see some errors in the console). Then I am delaying the alert 1 second, giving the refresh control enough time to end.

func updatedStatusFailed(notification: NSNotification) {
    DispatchQueue.main.async {
        self.refresher.endRefreshing()
    }
    self.helpers.delay(1.0, closure: {
        let alert = UIAlertController(title: "Error", message: "Error Description", preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    })
}

My delay function comes from a helpers class because I use it a few times in my app.

func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

In many cases you may be calling an api when the view loads/appears and have the pull to refresh logic. In this case you might want to add this line so that you only delay by a second if the refresher is refreshing:

let delayTime:Double = self.refresher.isRefreshing ? 1.0 : 0.0

UPDATE: 20/1/16

Although my somewhat hacky answer works, in the end I opted to have a section in my tableView to display errors, rather than the alert. It was a lot more code and complexity, but the UX is a lot better.

Patrick
  • 6,495
  • 6
  • 51
  • 78