Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get return value in dispatch block?

Tags:

swift

swift3

How can I get the return value from an asynchronous dispatch block?

I came up with this example code:

if let url = URL(string: "https://google.com/") {
    let data: Data? = ***SOME_ASYNC_AWAIT_DISPATCH_GROUP<T>*** { return try? Data(contentsOf: url) }
    print("Downloaded Data: \(data)")
}

Goal: Here, I want the async call to produce a result and store it to the data constant so that I can use it.

like image 812
LONELiE Avatar asked Nov 30 '16 03:11

LONELiE


3 Answers

I am simple using the completion method to do this. Test function download the data from url in background thread and after downloading the completion block run, it returns downloaded data, it may in any formate convert it in your formate.

func UpdateUI(){

        test { (data) in
          //data is value return by test function
            DispatchQueue.main.async {
                // Update UI
                //do task what you want.
                // run on the main queue, after the previous code in outer block
            }
        }
    }

    func test (returnCompletion: @escaping (AnyObject) -> () ){

        let url = URL(string: "https://google.com/")
        DispatchQueue.global(qos: .background).async {
            // Background work
            let data = try? Data(contentsOf: url!)
            // convert the data in you formate. here i am using anyobject.
            returnCompletion(data as AnyObject)
        }
    }

Hope it will help you.

like image 183
Amrit Tiwari Avatar answered Sep 16 '22 16:09

Amrit Tiwari


I found a solution.

// REFERENCED TO: https://gist.github.com/kylesluder/478bf8fd8232bc90eabd
struct Await<T> {
    fileprivate let group: DispatchGroup
    fileprivate let getResult: () -> T
    @discardableResult func await() -> T { return getResult() }
}
func async<T>(_ queue: DispatchQueue = DispatchQueue.global() , _ block: @escaping () -> T) -> Await<T> {
    let group = DispatchGroup()
    var result: T?
    group.enter()
    queue.async(group: group) { result = block(); group.leave() }
    group.wait()
    return Await(group: group, getResult: { return result! })
}

Call to like this.

let data = async{ return try? Data(contentsOf: someUrl) }.await()

OR

More simple:

@discardableResult func async<T>(_ block: @escaping () -> T) -> T {
    let queue = DispatchQueue.global()
    let group = DispatchGroup()
    var result: T?
    group.enter()
    queue.async(group: group) { result = block(); group.leave(); }
    group.wait()

    return result!
}

Call to like this.

let data = async{ return try? Data(contentsOf: someUrl) }

(And thanks for edit my question, Seaman.)

like image 44
LONELiE Avatar answered Sep 17 '22 16:09

LONELiE


This should work with a sync block

 var result:T? = nil
 DispatchQueue.global(qos: .background).sync {
     //Do something then assigne to result   
 }
 return result
like image 26
Shalom Friss Avatar answered Sep 18 '22 16:09

Shalom Friss