Trying to return value from firebase querysnaphsot completion handler inside function - swift

I'm trying to return a value produced from an asynchronous block of code (from my completion handler) for my function validateFields(), however I'm not sure how to do that.
func validateFields() -> Bool
{
//Other else if statements
//...
else if !(usernameTextField.text!.isEmpty)
{
var retVal = false
isUnique { (bool) in
retVal = bool
}
print("THIS IS THE RET VALUE: " + String(retVal))
//this print statement does not return the correct value
if retVal == false { return retVal }
}
errorLabel.text = " "
return true
}
As you can see, it doesn't work, I need to return bool in isUnique for my entire function.

You can't store the result of isUnique's closure then instantly return it, because isUnique will take as long as it takes to complete whatever task that is.
You want something like the following, where completion is called on all paths, but only once:
func validateFields(completion: (Bool) -> Void) {
//Other else if statements
//...
if ... {
/* ... */
} else if !(usernameTextField.text!.isEmpty) {
var retVal = false
isUnique { (bool) in
print("THIS IS THE RET VALUE: " + String(bool))
completion(bool)
}
} else {
errorLabel.text = " "
completion(true)
}
}
Caller:
validateFields { result in
print("result: \(result)")
}

Related

firestore query with bool as return in swift

I need to check if the following query return a true or false I have try with escaping but I receive an error:
here below the code of the function:
func checkBookingTime(user: UserModel, completion:#escaping(Bool) -> ()) {
if let userId = user.id {
db.collection("bookings").whereField("publisherUser", isEqualTo: userId).addSnapshotListener { querySnapshot, error in
if let querySnapshot = querySnapshot {
let count = querySnapshot.documents.count
if(count == 0) {
completion(true)
} else {
completion(false)
}
print("number of doc: \(querySnapshot.documents.count)")
}
}
}
}
and here is when I'm good to use it:
func loadBookingCheckTime(user: UserModel) -> Bool {
self.bookingRepository.checkBookingTime(user: user) { (isSuccess) in
if isSuccess {
print("si")
} else {
print("no")
}
}
}
but I receive the following error:
Cannot convert return expression of type '()' to return type 'Bool'
Can someone give me some hint?
Why dont u use just:
bookingRepository.checkBookingTime(user: user) { (isSuccess) in
if isSuccess {
print("si")
} else {
print("no")
}
}
You have your bool in isSucess.
func loadBookingCheckTime(user: UserModel) -> Bool can be skipped.
You need to use a completion handler in your loadBookingCheckTime if you want to do it that way. However, as #saro mentioned, you could just call it directly.

Checking the String whether it is the Number(Double) of

Question. It is necessary to make check the String whether it is the Number(Double)?
Exemple:
var s1:String = "df1231"
var s2:String = "1231,3123"
If s1.isDouble {
Println("True.This Number!")
} else {
Println("False.This not Number!") //Will give it
}
If s2.isDouble {
Println("True.This Number!") //Will give it
} else {
Println("False.This not Number!")
}
Not sure what your needs are exactly, but the most straightforward way to do it could be:
func isDouble(text:String) -> Bool {
guard let _ = Double(text.stringByReplacingOccurrencesOfString(",", withString: ".")) else { return false }
return true
}
isDouble("df1231") // returns false
isDouble("1231,3123") // returns true
You can copy paste it to Playground to see it work.

If let statement with multiple returns from function in swift

Say I have a function
func function1() -> (result:Bool, data:String){
return(false, "false")
}
and I want to use the return value of the Bool in an if let statement so,
if let value = function1 {
//code
} else {
//code
}
How would I get this to work? I can't seem to see it in the swift docs, as it just aludes to it being a returned tuple, which you can access with dot notation, but only if you set the return to be a tuple first - so for example this would work
var value = function1()
if value.result {
////code
} else {
//code
}
works, but I'd like to fit it all into the actual if else if possible. Any ideas?
I would suggest the use of a computed property.
func someFunc() {
if let value = computedProperty where value.result {
print(value.data)
} else {
// Do something else
}
}
var computedProperty: (result: Bool, data: String)? {
return (true, "FooBar")
}
or using a function
func someFunc() {
if let value = anotherFunc() where value.result {
print(value.data)
} else {
// Do something else
}
}
func anotherFunc() -> (result: Bool, data: String)? {
return (true, "FooBar")
}
Hope this helps :)
Swift 2.1 Properties
You could pattern match with a switch statement.
switch function1() {
case (true, let string):
print(string)
default:
// else stuff here
}
With this type on if you need optional return type from your function like this:
func function1() -> (result:Bool, data:String)? {
return(false, "false")
}
if let value = function1() {
//code
} else {
//code
}

Re-execute while loop after completion handler has been returned

I have a while loop i wish to keep executing if the returned number is 0. The problem is currently have is that the loop never stops since it doesnt wait for the completion handler to return its results (which takes a couple seconds). How can i only re execute the while loop after the if statement has been completed?
while loop
var empty = true
override func viewDidLoad() {
repeat {
str = iFunctions.generateRandomStringWithLengthOf(4) as String
iFunctions.getServerData(str){(msg)
in
if (msg > 0){
self.empty = false
print("not empty")
}
else{
print("empty")
}
self.count = msg!
print(self.count)
}
} while(empty)
}
function
func getServerData(q: String, completionHandler: (Int?) -> ()) -> () {
let params = [
"term": q
]
Alamofire.request(.GET, "URL", parameters: params)
.responseJSON { response in
if response.result.error == nil {
let json = JSON(response.result.value!)
//add data to struct
completionHandler(json["results"].count)
}
}
}
You shouldn't do this with a loop. That's the whole point of Alamofire, so you don't have to deal with threads and loops. You're working with high level instructions: callbacks.
It's actually very easy to solve your problem:
var empty = true
override func viewDidLoad() {
self.tryGettingDataFromServer()
}
func tryGettingDataFromServer(){
str = iFunctions.generateRandomStringWithLengthOf(4) as String
iFunctions.getServerData(str){(msg) in
if (msg > 0){
self.empty = false
print("not empty")
}
else{
// The closure keeps a reference to self and calls
// the tryGettingDataFromServer again if "empty"
// It will happen infinitely until "not empty"
self.tryGettingDataFromServer()
}
self.count = msg!
print(self.count)
}
}

Function not returning string

So I'm getting back to programming and I'm having an issue. My function is not returning a value when I'm storing a Value in it. Could you guys have a look and point my out why that is happening?
func getLocation() -> NSString {
manager = OneShotLocationManager()
var tempLocation: NSString = "" // created an empty string for the var
manager!.fetchWithCompletion {location, error in
if let locatie = location {
tempLocation = String(locatie.coordinate.latitude) + "," + String(locatie.coordinate.longitude)
print(tempLocation) // It stores a value here but will not show it on the return
} else if let err = error {
tempLocation = err.localizedDescription
}
self.manager = nil
}
return tempLocation // It's not returning anything here..
}
The completion starts after you exit the function, so that is the problem i guess. You return "" and then do the stuff inside completion code
Your function is not returning the value because the fetchWithCompletion is being executed after the return statement as it is asynchronous. You can amend your function by using a completion handler to get access the tempLocation once it has been set:
func getLocation(completion: (location: String) -> ()) {
manager = OneShotLocationManager()
var tempLocation: NSString = "" // created an empty string for the var
manager!.fetchWithCompletion {location, error in
if let locatie = location {
tempLocation = String(locatie.coordinate.latitude) + "," + String(locatie.coordinate.longitude)
print(tempLocation) // It stores a value here but will not show it on the return
} else if let err = error {
tempLocation = err.localizedDescription
}
self.manager = nil
completion(location: tempLocation)
}
}
You can implement this function in the following way:
getLocation { (location) -> () in
print(location)
}
You need to call getLocation and do your stuff inside the fetchWithCompletion closure
func getLocation() {
manager = OneShotLocationManager()
manager!.fetchWithCompletion {location, error in
if let locatie = location {
tempLocation = String(locatie.coordinate.latitude) + "," + String(locatie.coordinate.longitude)
//DO THE THINGS YOU NEED TO DO WITH THE LOCATION HERE
} else if let err = error {
tempLocation = err.localizedDescription
}
self.manager = nil
}
}
The closure provided to fetchWithCompletion() is called asynchronously - upon the completion of the manager's location fetch. Your function starts the manager fetching and then returns before the manager's fetch is complete; thus the initial assignment to tempLocation is return as "".
As the fetch is asynchronous, perhaps your getLocation() should also be asynchronous?
func getLocationAsynch (handler: (String) -> Void) {
OneShotLocationManager()!.fetchWithCompletion { location, error in
if let locatie = location {
handler (String(locatie.coordinate.latitude) + "," + String(locatie.coordinate.longitude))
} else if let err = error {
handler (err.localizedDescription)
} else {
handler ("")
}
}
}
The above prevents your code from blocking; perhaps when the location becomes available you just display it for the user?
If, however, you want to block. Use a dispatch_semaphore as:
// assuming dispatch_semaphore works in Swift
func getLocation () -> String {
let sem = dispatch_semaphore_create (0);
var result = ""
OneShotLocationManager()!.fetchWithCompletion { location, error in
if let locatie = location {
result = String(locatie.coordinate.latitude) + "," + String(locatie.coordinate.longitude)
} else if let err = error {
result = err.localizedDescription
}
dispatch_semaphore_signal(sem)
}
dispatch_semaphore_wait(sem)
return result
}