If I have to run a block of codes in background thread, how to make a function return the value after async blocks?

For example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func myFunction() {
var a: Int?

DispatchQueue.main.async {
var b: Int = 3
a = b
}

// wait until the task finishes, then print

print(a) // - this will contain nil, of course, because it
// will execute before the code above

}

Solution:

Use DispatchGroups to achieve this. You can either get notified when the group’s enter() and leave() calls are balanced:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func myFunction() {
var a: Int?

let group = DispatchGroup()
group.enter()

DispatchQueue.main.async {
a = 1
group.leave()
}

// does not wait. But the code in notify() gets run
// after enter() and leave() calls are balanced

group.notify(queue: .main) {
print(a)
}
}

or you can wait (and return):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func myFunction() -> Int? {
var a: Int?

let group = DispatchGroup()
group.enter()

// avoid deadlocks by not using .main queue here
DispatchQueue.global(attributes: .qosDefault).async {
a = 1
group.leave()
}

// wait ...
group.wait()

// ... and return as soon as "a" has a value
return a
}

Note: group.wait() blocks the current queue (probably the main queue in your case), so you have to dispatch.async on another queue (like in the above sample code) to avoid a deadlock.