firestore query with bool as return in swift - 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.

Related

Extend Optional to check whether it is nil or false

I want to extend the Optional class to return a Bool indicating whether self is nil or false. How do I do this?
I already have an extension for optional to check if it is empty or nil like this:
extension Optional where Wrapped: Collection {
var isNilOrEmpty: Bool {
return self?.isEmpty ?? true
}
}
So it needs to be something along those lines but I can't figure it out.
When in doubt, unwrap using guard:
extension Optional where Wrapped == Bool {
var isNilOrFalse: Bool {
guard let wrapped = self else { return true }
return !wrapped
}
}
Which can be shortened to:
extension Optional where Wrapped == Bool {
var isNilOrFalse: Bool {
return !(self ?? false)
}
}
but since short is not always the most readable, I would personally use explicit:
extension Optional where Wrapped == Bool {
var isNilOrFalse: Bool {
return self == nil || self == false
}
}
However, I would warn against using such extensions. They don't make your code more readable.
import Foundation
extension Optional where Wrapped == String {
var isNotBlank: Bool {
if let a = self, a.isNotEmpty {
return true
} else {
return false
}
}
var isBlank: Bool {
return !isNotBlank
}
}
extension Optional {
var isNil: Bool {
return self == nil
}
var isNotNil: Bool {
return self != nil
}
func ifLet(_ action: (Wrapped)-> Void) {
if self != nil {
action(self.unsafelyUnwrapped)
}
else { return }
}
func ifNil (_ action: ()-> Void) {
if self == nil { action() }
else { return }
}
func ifElse(_ notNil: ()-> Void, _ isNil: ()-> Void) {
if self != nil { notNil() }
else { isNil() }
}
func or<T>(_ opt: T) -> T {
if self == nil { return opt }
else { return self as! T }
}
mutating func orChange<T>(_ opt: T) {
if self == nil { self = opt as? Wrapped }
}
}
You don't need to do anything new. You can use != true on an optional Bool:
var aBool: Bool? = nil
if aBool != true {
print("aBool is nil or false")
}
That is legal and works. It works because nil is not equal to true.

How to check Observable count in rxswift?

I have this method return User observable
internal func getUser() -> Observable<User> {
let result = withRealm("getting user") { realm -> Observable<User> in
let realm = try Realm()
let user = realm.objects(User.self).first
return Observable.from(optional: user)
}
return result ?? .empty()
}
Now i want to have another method that returns me if user is loggedin, how it will be done?
private var _isLoggedIn: Observable<User> {
return getUser().count > 0 //error
}
I would suggest moving to enum to get rid of optionals on make it easier to manage:
enum LoginState {
case loggedIn(user: User)
case loggedOut
}
internal func getLoginState() -> Observable<LoginState> {
let user = withRealm("getting user") { realm -> User? in
let realm = try Realm()
return realm.objects(User.self).first
}
if let user = user {
return Observable.just(.loggedIn(user))
} else {
return Observable.just(.loggedOut)
}
}
private var _isLoggedIn: Observable<Bool> {
return getLoginState().map {
switch $0 {
case .loggedIn: return true
case .loggedOut: return false
}
}
}

Escaping completion handler never happens (Google Places API)

I'm building an app that uses the Google Places API. I currently have a button that, when tapped, gets the address of the current GPS location. The code is in my view controller:
var placesClient: GMSPlacesClient?
#IBAction func buttonTapped(_ sender: AnyObject) {
placesClient?.currentPlace(callback: { (placeLikelihoods, error) -> Void in
guard error == nil else {
print("Current Place error: \(error!.localizedDescription)")
return
}
if let placeLikelihoods = placeLikelihoods {
let place = placeLikelihoods.likelihoods.first?.place
self.addressLabel.text = place?.formattedAddress!.components(separatedBy: ", ").joined(separator: "\n")
}
})
print("Out of the brackets...")
}
When done this way, the function completes and "Out of the brackets..." is printed.
However, when I try moving this code out of the view controller and into a custom class and call it from the view controller, like below, everything within the "placesClient?.currentPlace(callback" block runs (and retrieves the correct address), but "Out of the brackets..." never gets printed and it never returns the value:
class LocationAPIService {
var placesClient: GMSPlacesClient? = GMSPlacesClient.shared()
func getCurrentLocation() -> GMSPlace? {
var thisPlace: GMSPlace?
placesClient?.currentPlace(callback: { (placeLikelihoods, error) -> Void in
guard error == nil else {
print("Current Place error: \(error!.localizedDescription)")
return
}
if let placeLikelihoods = placeLikelihoods {
let place = placeLikelihoods.likelihoods.first?.place
thisPlace = place
}
})
print("Out of the brackets...")
return thisPlace
}
}
Anybody know why this might be happening?
Fixed it. Here is the code I used for the method in my LocationAPIService class:
func setCurrentLocationPlace(completion: #escaping (_ result: Bool)->()) {
var placeFindComplete: Bool = false
placesClient?.currentPlace(callback: { (placeLikelihoods, error) -> Void in
guard error == nil else {
print("Current Place error: \(error!.localizedDescription)")
completion(true)
return
}
if let placeLikelihoods = placeLikelihoods {
let place = placeLikelihoods.likelihoods.first?.place
self.currentPlace = place
placeFindComplete = true
completion(true)
}
})
if (placeFindComplete == false) {
completion(false)
}
}
And here is the way I called it from the view controller:
locationAPIService?.setCurrentLocationPlace() { (locationFound) -> () in
if (locationFound == true) {
//Run code here that triggers once setCurrentLocationPlace() complete.
}

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
}

Swift How to wait for callback to finish before exiting function?

The problem I'm having on this request is the first function syncRequest always returns nil since the function exits before the (reply, error) comes back to fill out my return dictionary.
Is there a way for it to wait for the callback to return before returning out of my closure?
public typealias KKWatchSyncResponse = Dictionary<String, AnyObject>
func syncRequest() -> KKWatchSyncResponse? {
var syncResponseDict : KKWatchSyncResponse?
createRequest(KKWatchRequest.Sync, parameter: nil) { reply, error in
if reply == nil || error != nil {
return
} else {
syncResponseDict = KKWatchSyncResponse()
}
if let songInfo = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["songInfo"] as NSData) as NSDictionary? {
syncResponseDict!["songInfo"] = songInfo
}
if let albumArtImage = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["albumArt"] as NSData) as? UIImage {
syncResponseDict!["albumArtImage"] = albumArtImage
}
if let isPlaying = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["isPlaying"] as NSData) as? Bool {
syncResponseDict!["isPlaying"] = isPlaying
}
}()
return syncResponseDict
}
func createRequest(request:KKWatchRequest, parameter: KKWatchAPIRequestParameter?, callback:KKWatchAPICallback) -> KKWatchAPIParentRequest {
var requestDict : Dictionary<String, AnyObject> = [KKBOXWatchAppRequestType : request.rawValue]
if parameter != nil {
requestDict += parameter! //Combine 2 dictionaries
}
return { WKInterfaceController.openParentApplication(requestDict){ reply, error in
callback(reply, error)
}
}
}
Your help us much appreciated!
Could you have syncRequest() take a closure that gets called with the results when ready? Change the definition to something like:
func syncRequest(callback:(KKWatchSyncResponse?)->Void) { ... }
Then at the end of your createRequest() call, you could call the callback on syncResponseDict, since now it's been populated with your data... callback(syncResponseDict).
EDIT: Here's the solution I had in mind.
func syncRequest(callback:(KKWatchSyncResponse?)->Void) {
createRequest(KKWatchRequest.Sync, parameter: nil) { reply, error in
if reply == nil || error != nil {
callback(nil)
} else {
var syncResponseDict : KKWatchSyncResponse? = KKWatchSyncResponse()
if let songInfo = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["songInfo"] as NSData) as NSDictionary? {
syncResponseDict!["songInfo"] = songInfo
}
if let albumArtImage = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["albumArt"] as NSData) as? UIImage {
syncResponseDict!["albumArtImage"] = albumArtImage
}
if let isPlaying = NSKeyedUnarchiver.unarchiveObjectWithData(reply!["isPlaying"] as NSData) as? Bool {
syncResponseDict!["isPlaying"] = isPlaying
}
callback(syncResponseDict)
}
}()
}
It is straight forward to implement a locking variable. This is most helpful for unit tests that do some async network loading.
func waitingFunction()
{
//set a lock during your async function
var locked = true
RunSome.asyncFunction() { () -> Void in
//after your sync function remove the lock
locked = false
})
//wait for the async method to complete before advancing
while(locked){wait()}
//move on from the lock
doMoreStuff()
}
func wait()
{
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: 1))
}