Search code examples
iosswiftgrand-central-dispatch

How to change delay time for an object in DispatchQueue


I have a tableView where cells appear with certain delay. Delay depends on how many letters there are in text of each cell. So my question is if there is a way that I can change delay time if user does something (e.g. scrolls down tableView).

Ideally I want next cell to appear with no delay at all if tableView is scrolled down.

I guess the answer lays somewhere in DispatchQueue.main.async(execute: task). Though I am not sure if it executes just the next queued task or all tasks in the queue. (Apparently I need just the next task). Anyway with the code below my app crashes.

var task: DispatchWorkItem?
var lastContentOffset: CGFloat = 0

//Checking if tableView was scrolled.

override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
   if lastContentOffset < scrollView.contentOffset.y {
        print("Table view scrolled-down!")
        DispatchQueue.main.async(execute: task!)
   }
   else{
        print("Scrolled up")
   }
}

//Updating my tableView with delay

func updateTableView(nextPassageID: Int) {

    task = DispatchWorkItem {
         self.numberOfCells += 1
         let indexPath = IndexPath(row: nextPassageID, section: 0)
         self.tableView.insertRows(at: [indexPath], with: .fade)
    }

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: task!)
}

Any help would be greatly appreciated. Cheers!


Solution

  • How to change delay time for an object in DispatchQueue

    Bottom line, you don’t. If you want it to start sooner than previously scheduled, just cancel it and the dispatch a create new one without any delay associated with it.

    Alternatively, you can use a Timer, which you can schedule but also fire before the scheduled fire date occurs, it will run it and then invalidate it.

    Just be careful of strong reference cycles. For example, in your closures (whether DispatchWorkItem or closure-based timer, consider using [weak self] capture list, so that the closure doesn’t maintain a strong reference to self. Likewise, if you have an ivar to your DispatchWorkItem or Timer, consider (a) using a local var for the item/timer, (b) add that to your queue/runloop, and then (c) make your ivar a weak reference, so that when the item is run and/or the timer fires, that your ivar will be automatically released, avoiding hanging on to references beyond their useful lifespan.