How to Write Dispatch_After Gcd in Swift 3, 4, and 5

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

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).

dispatch_after - GCD in Swift?

A clearer idea of the structure:

dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)

dispatch_time_t is a UInt64. The dispatch_queue_t is actually type aliased to an NSObject, but you should just use your familiar GCD methods to get queues. The block is a Swift closure. Specifically, dispatch_block_t is defined as () -> Void, which is equivalent to () -> ().

Example usage:

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("test")
}

EDIT:

I recommend using @matt's really nice delay function.

EDIT 2:

In Swift 3, there will be new wrappers for GCD. See here: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

The original example would be written as follows in Swift 3:

let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
print("test")
}

Note that you can write the deadlineTime declaration as DispatchTime.now() + 1.0 and get the same result because the + operator is overridden as follows (similarly for -):

  • func +(time: DispatchTime, seconds: Double) -> DispatchTime
  • func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime

This means that if you don't use the DispatchTimeInterval enum and just write a number, it is assumed that you are using seconds.

How do I write GCD asyncAfter in Swift 4?

Trying in playground it doesn't give any issue, that is just "missing" is the "timer" reference.

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("Dispatching after")
}

DispatchQueue.main.asyncAfter(deadline: .now() + 3, qos: .userInteractive, flags: []) {
print("Dispatching after")
}

They both seems to work, are you sure that the problem isn't somewhere else?

How does DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) work in Swift 3?

OK, I found the answer to my own question in this thread:

How do I write dispatch_after GCD in Swift 3?

Apparently there is an override of the + operator that takes a DispatchTime and a double, treats the double as decimal seconds, and returns a resulting DispatchTime.

How do I dispatch_sync, dispatch_async, dispatch_after, etc in Swift 3, Swift 4, and beyond?

Since the beginning, Swift has provided some facilities for making ObjC and C more Swifty, adding more with each version. Now, in Swift 3, the new "import as member" feature lets frameworks with certain styles of C API -- where you have a data type that works sort of like a class, and a bunch of global functions to work with it -- act more like Swift-native APIs. The data types import as Swift classes, their related global functions import as methods and properties on those classes, and some related things like sets of constants can become subtypes where appropriate.

In Xcode 8 / Swift 3 beta, Apple has applied this feature (along with a few others) to make the Dispatch framework much more Swifty. (And Core Graphics, too.) If you've been following the Swift open-source efforts, this isn't news, but now is the first time it's part of Xcode.

Your first step on moving any project to Swift 3 should be to open it in Xcode 8 and choose Edit > Convert > To Current Swift Syntax... in the menu. This will apply (with your review and approval) all of the changes at once needed for all the renamed APIs and other changes. (Often, a line of code is affected by more than one of these changes at once, so responding to error fix-its individually might not handle everything right.)

The result is that the common pattern for bouncing work to the background and back now looks like this:

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
DispatchQueue.main.async {
self.imageView.image = image
}
}

Note we're using .userInitiated instead of one of the old DISPATCH_QUEUE_PRIORITY constants. Quality of Service (QoS) specifiers were introduced in OS X 10.10 / iOS 8.0, providing a clearer way for the system to prioritize work and deprecating the old priority specifiers. See Apple's docs on background work and energy efficiency for details.

By the way, if you're keeping your own queues to organize work, the way to get one now looks like this (notice that DispatchQueueAttributes is an OptionSet, so you use collection-style literals to combine options):

class Foo { 
let queue = DispatchQueue(label: "com.example.my-serial-queue",
attributes: [.serial, .qosUtility])
func doStuff() {
queue.async {
print("Hello World")
}
}
}

Using dispatch_after to do work later? That's a method on queues, too, and it takes a DispatchTime, which has operators for various numeric types so you can just add whole or fractional seconds:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
print("Are we there yet?")
}

You can find your way around the new Dispatch API by opening its interface in Xcode 8 -- use Open Quickly to find the Dispatch module, or put a symbol (like DispatchQueue) in your Swift project/playground and command-click it, then brouse around the module from there. (You can find the Swift Dispatch API in Apple's spiffy new API Reference website and in-Xcode doc viewer, but it looks like the doc content from the C version hasn't moved into it just yet.)

See the Migration Guide for more tips.

dispatch_after in swift explanation

Let's break it down into multiple statements:

let when = dispatch_time(DISPATCH_TIME_NOW, Int64(1000 * Double(NSEC_PER_MSEC)))
let queue = dispatch_get_main_queue()

dispatch_after(when, queue) {
self.redButton.highlighted = false
}

dispatch_after() enqueues the block for execution at a certain time
on a certain queue. In your case, the queue is the "main queue"
which is "the serial dispatch queue associated with the application’s main thread". All UI elements must be modified on the main thread only.

The when: parameter of dispatch_after() is a dispatch_time_t
which is documented as "a somewhat abstract representation of time".
dispatch_time() is an utility function to compute that time value.
It takes an initial time, in this case DISPATCH_TIME_NOW which
"indicates a time that occurs immediately", and adds an offset which
is specified in nanoseconds:

let when = dispatch_time(DISPATCH_TIME_NOW, Int64(1000 * Double(NSEC_PER_MSEC)))

NSEC_PER_MSEC = 1000000 is the number of nanoseconds per millisecond,
so

Int64(1000 * Double(NSEC_PER_MSEC))

is an offset of 1000*1000000 nanoseconds = 1000 milliseconds = one second.

The explicit type conversions are necessary because Swift does not
implicitly convert between types. Using Double ensures that it
works also in cases like

let when = dispatch_time(DISPATCH_TIME_NOW, Int64(0.3 * Double(NSEC_PER_SEC)))

to specify an offset of 0.3 seconds.

Summary: Your code enqueues a block to be executed on the main
thread in 1000 ms from now.

Update: See How do I write dispatch_after GCD in Swift 3 and 4? for how the syntax changed
in Swift 3.

Pass DispatchTime as an argument in DispatchAfter

This is what you want in Swift 3+:

let seconds = 2.0
// dispatchTime 2 seconds from now:
let dispatchTime: DispatchTime = DispatchTime.now() + seconds
DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
// code to be executed
}

How to use gcd barrier in iOS?

Whenever you create a DispatchQueue, whether serial or concurrent, it spawns its own thread that it uses to schedule and run work items on. This means that whenever you instantiate a MutiReadSingleWriteObject object, its queue will have a dedicated thread for synchronizing your setter and getObject method.

However: this also means that in your testMutiReadSingleWriteObject method, the queue that you use to execute the 100 getObject calls in a loop has its own thread too. This means that the method has 3 separate threads to coordinate between:

  1. The thread that testMutiReadSingleWriteObject is called on (likely the main thread),
  2. The thread that store.queue maintains, and
  3. The thread that queue maintains

These threads run their work in parallel, and this means that an async dispatch call like

queue.async {
store.getObject { ... }
}

will enqueue a work item to run on queue's thread at some point, and keep executing code on the current thread.

This means that by the time you get to running store.object = 1, you are guaranteed to have scheduled 100 work items on queue, but crucially, how and when those work items actually start executing are up to the queue, the CPU scheduler, and other environmental factors. While somewhat rare, this does mean that there's a chance that none of those tasks have gotten to run before the assignment of store.object = 1, which means that by the time they do happen, they'll see a value of 1 stored in the object.

In terms of ordering, you might see a combination of:

  1. 100 getObject calls, then store.object = 1
  2. N getObject calls, then store.object = 1, then (100 - N) getObject calls
  3. store.object = 1, then 100 getObject calls

Case (2) can actually prove the behavior you're looking to confirm: all of the calls before store.object = 1 should return nil, and all of the ones after should return 1. If you have a getObject call after the setter that returns nil, you'd know you have a problem. But, this is pretty much impossible to control the timing of.


In terms of how to address the timing issue here: for this method to be meaningful, you'll need to drop one thread to properly coordinate all of your calls to store, so that all accesses to it are on the same thread.

This can be done by either:

  1. Dropping queue, and just accessing store on the thread that the method was called on. This does mean that you cannot call store.getObject asynchronously
  2. Make all calls through queue, whether sync or async. This gives you the opportunity to better control exactly how the store methods are called

Either way, both of these approaches can have different semantics, so it's up to you to decide what you want this method to be testing. Do you want to be guaranteed that all 100 calls will go through before store.object = 1 is reached? If so, you can get rid of queue entirely, because you don't actually want those getters to be called asynchronously. Or, do you want to try to cause the getters and the setter to overlap in some way? Then stick with queue, but it'll be more difficult to ensure you get meaningful results, because you aren't guaranteed to have stable ordering with the concurrent calls.



Related Topics



Leave a reply



Submit