1

I want to be able to use the the currentVote Int outside of the block, where currentVote is a variable defined at the top of the class.

databaseRef.child("Jokes").child(currentKey).observeSingleEventOfType(.Value, withBlock: { (snapshot) in

           if let currentNumber = snapshot.value! as? [String: AnyObject] {

              let currentValue = (currentNumber["votes"] as? Int)!

             self.currentVote = currentValue


            }

        })

 //*Location* where i want to use currentVote with it's new value

Location is where I want to use the value of currentVote. When i print the value here, i am returned nil, and thereafter I will be returned the expected value. When I print the value inside the block, I get the expected value. I understand why this is, it's because the block is being executed off the main thread and therefore when i print outside of the block, the print is being executed before the block and so it has a value of nil. I know that to get it onto the main thread you have to use

dispatch_async(dispatch_get_main_queue(), {
            code
        })

However, I have nested my code in numerous different ways with this dispatch call, but haven't been able to obtain the new value of currentVote. I have searched through stack overflow and users have suggested making a function outside of the block, then calling this inside. However, their function involves

func printValue(value: Int) {

print(value)

}

Which, as you can see would be useless to me as I want to use the value outside of the block, not print it!

***Code altered according to Cod3rite suggestion****

func get(completion: (value: Int) -> Void) {

        databaseRef.child("Jokes").child(currentKey).observeSingleEventOfType(.Value, withBlock: { (snapshot) in

           if let currentNumber = snapshot.value! as? [String: AnyObject] {

              let currentValue = (currentNumber["votes"] as? Int)!

             self.currentVote = currentValue

            completion(value: self.currentVote!)

            }

        })

        }

//where I want to use currentVote

I have put it into a completion as suggested, but I still don't know how to obtain the variable!

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
pho_pho
  • 672
  • 11
  • 30
  • anything deal with asynchronous need to use `completion` in order to return the value. can refer my answer here http://stackoverflow.com/questions/38113280/get-the-value-of-variable-out-of-closure-swift/38113412#38113412 – xmhafiz Jul 17 '16 at 14:53
  • @cod3rite I think I have made the changes according to your other post, but I still can't use the currentVote value. The changes are in my question above. Thanks very much for your time, I'd appreciate it if you could provide me with a complete answer. – pho_pho Jul 17 '16 at 15:13
  • You can't access that variable where you want to access it. It won't be ready when your control flow is there. You need to do whatever you want with the variable inside the block, when it's ready. – Aaron Brager Jul 17 '16 at 15:17
  • ("Can't" is not technically accurate, but you should assume for now that it is.) – Aaron Brager Jul 17 '16 at 15:19
  • @AaronBrager Ok, so I'm using firebase and i wanted to update the value of a particular piece of JSON data in my tree using the currentVote variable. So you're suggesting I just do this within the current observeEvent block? I thought that observing an event and then updating data within that call might be bad practice? I'm not sure why just guessing, or is this OK? – pho_pho Jul 17 '16 at 15:22
  • Yes, start with that. If your completion blocks get too big or repetitive you can refactor the code into functions, but you can worry about that later. For now get it working. – Aaron Brager Jul 17 '16 at 15:24
  • @pho_pho the `get` function there is for that question. the function name should follow yours – xmhafiz Jul 17 '16 at 15:25
  • Ok so as i understand if u want to retrieve data from Firebase, you can only work with that data within the retrieval block, unless you place the retrieval block in the viewDidLoad as this will be executed first. This is because the retrieval block will always be completed last if it is outside of the vDL. This just seems a bit limiting to me. I would've thought that you would be able to request the data, then set that data to a global variable and use the data through that variable anywhere else... – pho_pho Jul 17 '16 at 15:44
  • In your completion handler, you can store the data in a property for later use. You just can't access it where you're trying to, which is right after the process to get the data started – Aaron Brager Jul 17 '16 at 16:01

1 Answers1

1

You almost got it right. But here are a little modifications you need to do:

func get(completion: (value: Int) -> Void) {

        databaseRef.child("Jokes").child(currentKey).observeSingleEventOfType(.Value, withBlock: { (snapshot) in

           if let currentNumber = snapshot.value! as? [String: AnyObject] {

              let currentValue = (currentNumber["votes"] as? Int)!
               completion(value: currentValue)

            }


        })

        }

Now when you want to call this get, do this:

get { value in
 //Now you have your value retrieved from firebase and you can use it however you want.
 print(value)
 self.currentVote = value
//your other code
}
Mtoklitz113
  • 3,828
  • 3
  • 21
  • 40
  • Thanks Dershowitz, very nice of you to provide a complete answer. In the end, i didnt use a completion handler, i just placed my code underneath the data retrieval, is there anything wrong with doing it this way? My code involved increasing the Int value by 1 and then saving over the currently stored value on the JSON tree. – pho_pho Jul 17 '16 at 17:35
  • There is but one problem. When an error occurs, your code will fail as there will be no `Int` to return from the JSON. – Mtoklitz113 Jul 17 '16 at 17:37
  • Ok i understand, thanks very much for your time and help! – pho_pho Jul 17 '16 at 18:05
  • Anytime! Happy coding :) – Mtoklitz113 Jul 17 '16 at 18:05