Swift Closure Not Setting Variable

Swift closure not setting variable

.observeSingleEvent is working async.

You can do something like this:

func getRetname(completion: @escaping(_ retName: String) -> Void) {
if let uid = FIRAuth.auth()?.currentUser?.uid {
FIRDatabase.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
if let name = dictionary["name"] as? String {
ret_name = name
print(ret_name)
completion(ret_name)
}
}
})
}

Then, you can use it everywhere you want:

getRetname(completion: { ret_name in 
// ret_name - your data
})

Hope it helps

Can't assign a value to variable inside of closure Swift

Once it is a Async call - you cannot synchronously return the value from the function. You should accept a callback to the function that will accept the count. That callback function or closure will be passed the value asynchronously.

func getEventCount (callback: @escaping(Result<Int, Error>) -> Void) {
db.collection("Events").whereField("owner", isEqualTo: currentUser.email).getDocuments { (snapshot, error) in
if error != nil {
let result = Result.failure(error)
callback(result)
}else if let snapshot = snapshot {
let result = Result.success(snapshot.count)
callback(result)
} else {
let result = Result.failure(SomeCustomAppError)
callback(result)
}
}
}

Then you can call this function passing in a callback

self.getCount() { result in
switch result {
case .success(let count): /// use count
print(count)
// only here u can assign the count value to ur variable
case .error(let error): /// handle error
print(error.localizedDescription)
}
}

Note: In the above I've used the Result datatype from Swift standard library - https://developer.apple.com/documentation/swift/result so that both error
or result can be passed back

Cannot change variable from a closure in the same class [swift 3.0]

I got null array [] after this function, just like the function didn't do anything.

That's right, the function did not do anything. More precisely, the function did not do anything yet. Checking the value after the function is premature, because the callback is executed asynchronously, when the data arrives.

You need to split your code into two parts:

  • The first part initiates the call, and gives it a callback that sets properties to the results received from the call
  • The second part processes the results, displaying the properties or doing whatever else you planned to do

Once the callback is done setting the properties, it needs to initiate the call for the second part, which makes use of these properties.

func getServiceType() { // Part 1
...
self.serviceTypeName = serviceName
dispatch_async(dispatch_get_main_queue()) {
processServiceName()
}

}

func processServiceName() { // Part 2
... // Do things with self.serviceTypeName
}

Why can I not modify a variable declared outside a closure?

It's because data is loaded from Firestore asynchronously, and your main code continues to run while that is happening. It's easiest to see by placing a few log statements:

let docRef = db.collection("colleges").document("UMD")
print("Before starting to get data")
docRef.getDocument { ( document, error) in
print("Got data")
}
print("After starting to get data")

When you run this code, it prints:

Before starting to get data

After starting to get data

Got data

This is probably not the order you expected, but it does completely explain why your code doesn't work. By the time your pickerData.append(docData) runs, the docData = document!.get("Name") as! String hasn't run yet.

For this reason, any code that needs data from the database needs to be inside the closure, or be called from there:

let docRef = db.collection("colleges").document("UMD")
var docData = ""
docRef.getDocument { ( document, error) in
if error == nil {
docData = document!.get("Name") as? String ?? "No Name"

pickerData.append(docData)
picker.delegate = self
picker.dataSource = self
} else{

}
}

Also see:

  • Asign value of a Firestore document to a variable
  • Using Firestore DB, how can I break out of a for loop inside of a snapshot listener when a certain condition is met?, which also shows using a custom closure to keep your own code outside of the getDocument closure.
  • Storing asynchronous Cloud Firestore query results in Swift, showing using a dispatch group to keep the code

Swift variable declared outside closure is updated inside closure but when accessed outside closure it returns the default value?

Please use tabs to make your code easier readable.

Anyway geocoder.geocodeAddressString(address) is a method with a callback and in this callback method you have the placemark. Your return will not wait for that callback since it will take time to calculate the coordinates hence it returns 0.0 which you set at the start.


Edit: longer version since you asked in a comment:

CLGeocoder()'s function geocodeAddressString has in fact 2 parameters: the adress and a socalled callback. A callback is simply a method called when the task (in this case calcualting the placemark) finishes. Swift lets you write the callback in "swifty" syntax but actually it looks like

geocoder.geocodeAddressString(address, callAfterFinishGeocoding)

func callAfterFinishGeocoding(_ placemark: Placemark) {
// do stuff with placemark
}

as you can see we pass the geocode function another function to be called when done. The parameters of callAfterFinishGeocoding are defined in geocodeAddressString. It will look similar to this:

callback: @escaping (_ placeMark: Placemark) -> Void

This would mean the callback should be a function accepting a placemark and returning Void. Jump to the definition of the method see what kind of function it wants as parameter.

also read more here: https://stackoverflow.com/a/46245943/13087977

How do I set the return value of a closure function to a variable?

Try to set value of x variable inside of the closure:

loadData1(onCompletion: { (json) in
x = json
})

In your approach variable x initialized with a closure, that's why you received a warning.

Until closure will be executed, variable x have default value var x = [[String: String]]()
or remain unresolved if you did not provide default value along with declaration.

Assign Value from Closure to Variable Swift

change var userId: Int to var userId: Int!

The reason is that the closure is expecting a value to be in the variable when you "capture it". By using a forcefully unwrapped variable, the closure will be able to capture it as it holds a value of nil, which you can then assign a value to when the closure is called.



Related Topics



Leave a reply



Submit