0

I have a website query to get updated "Alert" statuses

I have an AlertManager with an AlertManagerDelegate protocol, and I am implementing this protocol in an AlertsTableViewController

One of the functions of this protocol is "didUpdateAlerts" as seen below, which is ultimately triggered after a successful query following a pull-to-refresh

func didUpdateAlerts(alerts: [String:String]){
    
    DispatchQueue.main.async {
        self.serviceDictionary = alerts
        self.tableView.reloadData()
    }
}

I would like to stick an endRefreshing with a one second delay following reloading the tableView data (for a smoother user experience)

Because the data is queried very quickly, if I add the endRefreshing below the reloadData() call, the refreshing animations ends almost instantaneously. How can I implement the delay?

Edited code -- appears to work but sometimes the print statement prints more than once, and sometimes the delay is still shorter than the assigned time

DispatchQueue.main.async {
        self.serviceDictionary = alerts
        self.tableView.reloadData()
        //self.perform(#selector(self.stopRefreshing), with: nil, afterDelay: 5)
        DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
            self.refreshAlertsControl.endRefreshing()
            print("After 3 sec delay - alertRefresh")
        }
}
Shonie
  • 35
  • 5

1 Answers1

0

You can use asyncAfter func to submit a work item onto a dispatch queue for asynchronous execution after a specified time. You probably do not need a whole second, usually 0.3 of a second is enough but the example shows a 5 second execution delay.

  DispatchQueue.main.async {
     self.tableView.reloadData()
     print("Before delay")
     DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
        self.refreshControl.endRefreshing()
         print("After 5 sec delay")
     }
  }
Mishka
  • 502
  • 5
  • 15
  • I tried 5 seconds for the sake of testing -- but it still doesn't do the full 5 seconds if I place this code beneath my code within the didUpdateAlerts `code` func didUpdateAlerts(alerts: [String:String]){ DispatchQueue.main.async { self.serviceDictionary = alerts self.tableView.reloadData() } DispatchQueue.main.asyncAfter(deadline: .now() + 5){ self.refreshAlertsControl.endRefreshing() } } `code` – Shonie Oct 26 '21 at 01:02
  • I added a full code example, this will certainly work if you have your refresh control and tableview and everything setup correctly, please modify your. question with the full code. You can test the code snippet I provided in xCode Playgrounds and use a timer. – Mishka Oct 26 '21 at 01:16
  • Thanks Mishka - I've adopted your suggestion. It's still not 100% reliable in that the endRefreshing sometimes occurs before the delay time, and sometimes the print statement prints multiple times (unsure why), but it works well enough so marking as solved – Shonie Oct 26 '21 at 23:53
  • @Shonie I would suggest looking into what is calling your didUpdateAlerts func, is it a callback func that might be called multiple times? Is there anything else happening concurrently on the main thread? Also are you setting your refresh control on the tableView or is it a custom widget? all those things can mess with it. If you solve them the code provided will work as expected. It is never good if something is being called multiple times and you do not know why, can lead to future unpredictable behavior. Good luck! – Mishka Oct 27 '21 at 01:04
  • @Shonie oh you did mention that it is a protocol callback so seems like you are getting the whole thing called multiple times, look into this for sure, its attempting to reload your tableView multiple times as well and just wasting main thread resources. Cheers! – Mishka Oct 27 '21 at 01:06
  • good point! Turned out to be the location manager. Used the boolean suggest in below post to fix: https://stackoverflow.com/questions/33492023/locationmanager-didupdatelocations-fires-twice-on-device-only-once-on-simulator – Shonie Oct 30 '21 at 21:50