Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write dispatch_after GCD in Swift 3, 4, and 5?

In Swift 2, I was able to use dispatch_after to delay an action using grand central dispatch:

var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))  dispatch_after(dispatchTime, dispatch_get_main_queue(), {      // your function here  }) 

But this no longer seems to compile since Swift 3. What is the preferred way to write this in modern Swift?

like image 956
brandonscript Avatar asked Jun 14 '16 01:06

brandonscript


People also ask

What is Dispatchqueue in Swift?

Dispatch queues are FIFO queues to which your application can submit tasks in the form of block objects. Dispatch queues execute tasks either serially or concurrently. Work submitted to dispatch queues executes on a pool of threads managed by the system.

What is DispatchWorkItem?

Overview. A DispatchWorkItem encapsulates work to be performed on a dispatch queue or within a dispatch group. You can also use a work item as a DispatchSource event, registration, or cancellation handler.

How do I add a delay in Swift?

To add a delay to your code we need to use GCD . GCD has a built in method called asyncAfter , which will allow us to run code after a given amount of time. In the above code, Before delay will be printed out first and after 2 seconds, Async after 2 seconds will be printed.


2 Answers

The syntax is simply:

// to run something in 0.1 seconds  DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {     // your code here } 

Note, the above syntax of adding seconds as a Double seems to be a source of confusion (esp since we were accustomed to adding nsec). That "add seconds as Double" syntax works because deadline is a DispatchTime and, behind the scenes, there is a + operator that will take a Double and add that many seconds to the DispatchTime:

public func +(time: DispatchTime, seconds: Double) -> DispatchTime 

But, if you really want to add an integer number of msec, μs, or nsec to the DispatchTime, you can also add a DispatchTimeInterval to a DispatchTime. That means you can do:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {     os_log("500 msec seconds later") }  DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(1_000_000)) {     os_log("1m μs seconds later") }  DispatchQueue.main.asyncAfter(deadline: .now() + .nanoseconds(1_500_000_000)) {     os_log("1.5b nsec seconds later") } 

These all seamlessly work because of this separate overload method for the + operator in the DispatchTime class.

public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime 

It was asked how one goes about canceling a dispatched task. To do this, use DispatchWorkItem. For example, this starts a task that will fire in five seconds, or if the view controller is dismissed and deallocated, its deinit will cancel the task:

class ViewController: UIViewController {      private var item: DispatchWorkItem?      override func viewDidLoad() {         super.viewDidLoad()          item = DispatchWorkItem { [weak self] in             self?.doSomething()             self?.item = nil         }          DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!)     }      deinit {         item?.cancel()     }      func doSomething() { ... }  } 

Note the use of the [weak self] capture list in the DispatchWorkItem. This is essential to avoid a strong reference cycle. Also note that this does not do a preemptive cancelation, but rather just stops the task from starting if it hasn’t already. But if it has already started by the time it encounters the cancel() call, the block will finish its execution (unless you’re manually checking isCancelled inside the block).

like image 169
Rob Avatar answered Oct 05 '22 18:10

Rob


Swift 4:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {    // Code } 

For the time .seconds(Int), .microseconds(Int) and .nanoseconds(Int) may also be used.

like image 22
Sverrisson Avatar answered Oct 05 '22 17:10

Sverrisson