Eric
Eric

Reputation: 682

iOS async function not in order

I'm new in async stuff in swift, ans I'm trying to implement a simple async call to a function.

import UIKit

func doAsyncStuff ( completionHandler: (_ result: Double) -> Void) {
    print("start async")
    sleep(5)   // to simulate long work
    let result: Double = 123.456
    completionHandler(result)
}

print("A")

doAsyncStuff() { result in
    print(result)
}

print("B")

When I execute it, I get

A
start async
123.456
B

As the func is called asynchronously, I would have expected to get

A
start async
B
123.456

Where did I go wrong ? Thanks a lot

Upvotes: 1

Views: 331

Answers (4)

Chris
Chris

Reputation: 4411

Your function is not asynchronous. Each line of code is being run synchronously (i.e. waiting for the line before to complete before executing). So the sleep(5) pauses execution in the middle of the function and print("B") is not called until after the function returns.

You can use Grand Central Dispatch (GCD) to run code asynchronously on a different thread. Here is an example:

import UIKit

func doAsyncStuff ( completionHandler: (_ result: Double) -> Void) {
    DispatchQueue.global(qos: .background).async { [weak self] in
        print("start async")
        sleep(5)
        let result: Double = 123.456
        completionHandler(result)
    }
}

print("A")

doAsyncStuff() { result in
    print(result) // This is your completion handler code
}

print("B")

Upvotes: 2

Adi.S
Adi.S

Reputation: 280

Use DispatchQueue.main.asyncAfter for an asynchronous call in swift. So your code should look like..

func doAsyncStuff ( completionHandler: (_ result: Double) -> Void) {
    print("start async")
    DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    // your code goes from here
        let result: Double = 123.456
        completionHandler(result)
    }

}

Upvotes: 1

Anis R.
Anis R.

Reputation: 6922

Beware, you are calling your function on the same thread, therefore it will be synchronous!

To call it in an asynchronous fashion, create a background thread/task, and call your function from that background thread. One way of doing it:

print("A")
DispatchQueue.global(qos: .background).async {
    //this is a background thread, do in it your async stuff
    doAsyncStuff() { result in
        print(result)
    }
}
print("B")

Upvotes: 1

David Pasztor
David Pasztor

Reputation: 54795

The issue is that you're calling sleep, which is a synchronously blocking function, so you block the main thread for 5 seconds and nothing else can be executed in the meantime. You should use DispatchQueue.asyncAfter to test simple async calls.

You can also know that your function is not asynchronous, since you didn't receive a compiler error for not marking your closure as @escaping, which you need to do for async completion handlers.

func doAsyncStuff(completionHandler: @escaping (_ result: Double) -> Void) {
    print("start async")
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        completionHandler(123.456)
    }
}

Upvotes: 3

Related Questions