0

I'm having a problem with this Swift function and although I'm sure the solution is fairly straightforward I cannot figure out what is wrong. Here is the code:

static func isArtist(user:FIRUser) -> Bool? {
    var artist: Bool?
    database.child("users").child(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
        artist = true //retrieves bool, simplified for example
    }) { (error) in
        print("isArtist - data could not be retrieved - EXCEPTION: " + error.localizedDescription)
    }
    return artist
}

The function returns nil every time, when logically I would think it would return true. Is this a problem with nested functions? How can I return content in the nested function? The database is the implementation of the Swift Firebase SDK, and the function should only return nil if no such object can be retrieved (for this example, if artist is nil). Thanks.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Tim Lupo
  • 259
  • 2
  • 9
  • Your function returns immideatly, while closure looks like continue executing in other thread. You are assigning artist = true in callback, already out of function scope. – Yury Aug 16 '16 at 21:56
  • Possible duplicate of [Returning data from async call in Swift function](http://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function) – dan Aug 16 '16 at 22:05

2 Answers2

2

Use completionBlock: to handle your situation , The reason why this is going to return you a nil is because you have declared your artist variable as optional , and it takes some time to retrieve data from any backend(asynchronous calls) thus executing return artist even before you could retrieve some value from database:-

Use :-

static func isArtist(user:FIRUser, completionBlock : ((isArtistBool : Bool)-> Void)) {
    database.child("users").child(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
             completionBlock(isArtistBool : true) //returns Bool in completionHnadler

        }) { (error) in

           print("isArtist - data could not be retrieved - EXCEPTION: " + error.localizedDescription)
          }

}

When you would call your function isArtist :-

isArtist(FIRAuth.auth()!.currentUser, completionBlock : {(isArtistBool) in 
 //Will return `isArtistBool` in completionHandler
 ..//rest of the code
})
Dravidian
  • 9,945
  • 3
  • 34
  • 74
0

Remember, you are fetching value of artist Asynchronously. It means the data might be available in near future but not sure when. so, this Asynchronous function runs in background thread and the programme continue to execute, hence returns nil.

database.child("users").child(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
        // this is asynchronous block. snapshot is available in near future.
    })

so instead of return use your completion block:

database.child("users").child(user.uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
             completionBlock(isArtistBool : true)
        })

and yeah, dont forget to remove -> Bool form the function, you dont need that when you are using completionBlock.

when using completion block your function signatures becomes like this:

isArtist(user: FIRUser, completionBlock: () -> FIRUser)) {

}

you can call this function as:

SomeClass.isArtist(user: FIRUser, completionBlock: () -> FIRUser){

  // your  user is available here after the value is fetched from firebase.
}

I hope this helps.

Ccr
  • 686
  • 7
  • 25