4

Please have a look into the code below:

backgroundthread.async {
    return self.mycallback() //return string, int etc
}

I want to return a value from an async block. I don't want any completion handler or any other workaround.

func getAppConfigFromDB(_ key: String) -> String 
{
   let value = String()
   backgroundthread.async {
      let inst = AppConfigDB.init(_APP_CONFIG_DB_PATH)
      value = inst.getConfigurationInfo(key) // I want to return from here.
   }
   return value
}


getAppConfigFromDB("path")
vikkuu
  • 232
  • 4
  • 11
  • 2
    You have no choice but to use a completion handler. You can't return a value from an async call. – rmaddy Sep 12 '18 at 05:18
  • ok, is there any work around or custom template, we can use. – vikkuu Sep 12 '18 at 05:20
  • 1
    I agree with @rmaddy, completion handler is the only way to handling the results when the async task completes. They named it well! – SagarScript Sep 12 '18 at 05:20
  • Why do you wish to avoid a completion handler? What problem are you trying to solve where the simplest and proper solution is to be avoided for some reason? – rmaddy Sep 12 '18 at 05:22
  • Could you provide me completion handler, I want to see. – vikkuu Sep 12 '18 at 05:31
  • The way to get a return value from your function is to change the async block to a synchronous block, or an inefficient workaround to do the same thing. – hotpaw2 Sep 12 '18 at 05:35
  • 2
    There are countless example here and in the Swift APIs. – rmaddy Sep 12 '18 at 05:36
  • @hotpaw2, yes, I can try with sync block. Its long way to change my code but thats fine. Thanks. !! – vikkuu Sep 12 '18 at 05:40

3 Answers3

9

Like @rmaddy said, you have no other way than to use completion handlers.

func getAppConfigFromDB(_ key: String, completion: @escaping ((String) -> Void)) {
    let value = String()
    backgroundthread.async {
        let inst = AppConfigDB.init(_APP_CONFIG_DB_PATH)
        value = inst.getConfigurationInfo(key) // I want to return from here.
        completion(value)
    }
}

You call the method like this.

getAppConfigFromDB("") { (value) in
    // Use value to do something
}
Rakesha Shastri
  • 11,053
  • 3
  • 37
  • 50
1

Your function would need a closure like so

func getAppConfigFromDB(_ key: String, completion: @escaping (String?) -> Void) {
    backgroundthread.async {
        completion("string here")
    }    
}

When you call your function you would do

getAppConfigFromDB("key") { (returnedString) in
    //returnedString is Optional("string here")
}
Sean
  • 1,534
  • 12
  • 20
0

What you are describing with return self.mycallback() is something like in

TypeScript:

String text = await someTask();

or in C#:

String text = someTask().result;

and from an async function:

String text = await someTask();

However this concept does not exist in swift (and i think Java too).

The only other method I can think of other than using a completion handler, is passing the results to another function (NOTE: If you intend on working on the main thread/UI Thread you will get an exception - you will need to wrap your call in DispatchQueue.main.async {/*Do stuff...*/}) like so

    func startAsync {
        let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
        let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
            guard let data = data else { return }
            guard let jsonString = String(data: data, encoding: .utf8) else { return }
            DispatchQueue.main.async {
                self.setResults(text: jsonString);
            }
        }
        task.resume()
    }

    func setResults(text: String?){
        textView.text = text;
    }

full project: https://github.com/AppLogics/SwiftAsyncTaskWithoutCompletionHandler

SagarScript
  • 1,145
  • 11
  • 15