How to Return Value from Async Block in Swift

How I can return value from async block in swift

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
}

How can i return value from async block?

You can pass completion closure and after success or failure request execute it.

func xmlRequest(_ id:Int, completion: @escaping ((String) -> Void)){
var array1:Array<Any> = Array<Any>();
array1.append("body" as Any);
array1.append("date" as Any);
array1.append("author_id" as Any);

let con:NSDictionary = NSDictionary();
var field2:Array<Any> = Array<Any>();
field2.append([["id", "=", [id]]]);
let url = Login.BASEURL+XMLRPC_SERVICE_OBJECT;
let param3 = [Login.DATABASE, Login.LOGIN_ID, Login.PASSWORD, "mail.tracking.value","search_read",field2,con] as [Any];

AlamofireXMLRPC.request(url, methodName: "execute_kw", parameters: param3).responseXMLRPC { (response: DataResponse<XMLRPCNode>) in
var valueToReturn:String = "default"
switch response.result {
case .success(let value):
valueToReturn = "success"
case .failure(let error):
valueToReturn = "error"
}

completion(valueToReturn)
}
}

More about closures you can read at Apple documentation =)

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

swift calling async function without a return value

What you're describing is a Task. For example:

Task { await `do`() }
stuff()

This will run do() concurrently with stuff(). If you need to keep track of when do() completes, you can await the task's value:

let task = Task { await `do`() }
stuff()
await task.value // Doesn't actually return anything, but will block

This kind of Task runs in the context of the current Actor, which is usually what you want. If you want something independent of the current Actor, you can use Task.detached() instead.

If you've previously used DispatchQueues, in many of the places you would have written queue.async { ... }, you can now write Task { ... }. The new system is much more powerful, but it maps fairly nicely to the old system if you want it to.

Can Swift return value from an async Void-returning block?

You should employ asynchronous (ie, escaping) completion handler yourself:

class func checkIfUserExists(uid: String, completion: @escaping (Bool) -> Void) {
userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value) { snapShot in
if snapShot.value is NSNull {
completion(false)
} else {
completion(true)
}
}
}

You can then call this like so:

MyClass.checkIfUserExists(uid) { success in
// use success here
}

// but not here

In your revised question, you demonstrate the use of dispatch groups to make this asynchronous method behave synchronously. (Semaphores are also often used to the same ends.)

Two issues:

  1. This will deadlock if they dispatch their completion handler back to the main queue (and in many cases, libraries will do this to simplify life for us), because you're coincidentally blocking the very same thread they're trying to use. I don't know if that's what they've done here, but is likely.

    If you want to confirm this, temporarily remove dispatch group and then examine NSThread.isMainThread and see if it's running in main thread or not.

  2. You never should block the main thread, anyway. They provided an asynchronous interface for good reason, so you should use asynchronous patterns when calling it. Don't fight the asynchronous patterns, but rather embrace them.

Swift write an async/await method with return value

Thanks, vadian comment. I used a closure as an input parameter of the method.

// MARK: - PassCode Methods
func checkPassCode(completionHandler:@escaping (_ flag:Bool) -> ()) {
let storePin = getStorePin()
let userPin = self.pin.joined(separator: "")
AsymmetricCryptoManager.sharedInstance.decryptMessageWithPrivateKey(storePin as Data) { (success, result, error) -> Void in
if success {
let pin = result!
print("userPin is: \(userPin)")
print("storePin is: \(pin)")
completionHandler(userPin == pin)
} else {
print("Error decoding base64 string: \(String(describing: error))")
completionHandler(false)
}
}
}

func getStorePin() -> NSData {
if let pin = self.keychain.get("pin") {
return NSData(base64Encoded: pin, options: []) ?? NSData()
}
return NSData()
}

and then call this method:

checkPassCode { success in
if success {
print("sucess")
} else {
print("not sucess!")
}
}

return value from completion handler is not updated in DispatchQueue.main.async block

The call of completion is at the wrong place. Move it into the completion closure of the data task after the print line

    // prints value
print("updated estimate: ", self.avgMonthlyAcKw)
completion(self.avgMonthlyAcKw)

and delete it after resume

dataTask.resume()

completion(self.avgMonthlyAcKw)

}

iOS - Swift - Function that returns asynchronously retrieved value

Yes, it is possible to do this. Its called a closure, or more commonly a callback. A callback is essentially a function that you can use as an argument in another functions. The syntax of the argument is

functionName: (arg0, arg1, arg2, ...) -> ReturnType

ReturnType is usually Void. In your case, you could use

result: (image: UIImage?) -> Void

The syntax of calling a function with one callback in it is

function(arg0, arg1, arg2, ...){(callbackArguments) -> CallbackReturnType in
//code
}

And the syntax of calling a function with several callbacks is (indented to make it easier to read)

function(
arg0,
arg1,
arg2,
{(cb1Args) -> CB1Return in /*code*/},
{(cb2Args) -> CB2Return in /*code*/},
{(cb3Args) -> CB3Return in /*code*/}
)

If your callback function escapes the main function (the callback is called after the main function returns), you must add @escaping in front of the callback's argument type

You're going to want to use a single callback that will be called after the function returns and that contains UIImage? as the result.

So, your code could look something like this

func imageFromFile(file: PFFile, result: @escaping (image: UIImage?) -> Void){
var image: UIImage?

file.getDataInBackgroundWithBlock() { (data: NSData?, error: NSError?) -> Void in
//this should be 'error == nil' instead of 'error != nil'. We want
//to make sure that there is no error (error == nil) before creating
//the image
if error == nil {
image = UIImage(data: data!)
result(image: image)
}
else{
//callback nil so the app does not pause infinitely if
//the error != nil
result(image: nil)
}
}
}

And to call it, you could simply use

imageFromFile(myPFFile){(image: UIImage?) -> Void in
//use the image that was just retrieved
}

how to use DispatchGroup to return a async value from a function

You need

class ViewController: UIViewController {

var coffeeMachineName = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

dev.adData.getMachineName { (mName) in
print("machine name from wbmanager: \(mName)")
self.coffeeMachineName = mName
DispatchQueue.main.async {
pickerView.reloadAllComponents()
}
}


}

private func _pv(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String {

let dev = self.pickerDevices[row]
let id = dev.internalUUID
guard let name = dev.name
else {
return "\(id)"
}
return "\(name) \(self.coffeeMachineName)"

}


}


Related Topics



Leave a reply



Submit