0

I have a var declared and I can retrieve the value from Firebase Database but when I then print the var in ViewDidLoad, it is empty, I don't understand what's wrong. Thanks everyone This is the answer I get when I print the var : this is the language

//
var language: String = ""

//
func getUserLanguage(completion:((String) -> Void)?) {
    let ref = Database.database().reference()
    let uid = Auth.auth().currentUser!.uid
    ref.child("users").child(uid).observe(.value, with: { (snapshot) in
       let value = snapshot.value as? NSDictionary
       let languageResult = value?["language"] as? String ?? ""
       completion?(languageResult)
    }
)}

//
getUserLanguage { (languageResult) in
   self.language = languageResult
}

// I print the value in ViewDidload
print("this is the language\(self.language)")
Jay
  • 34,438
  • 18
  • 52
  • 81
  • How are you getting nil when you assign empty string with `value?["language"] as? String ?? ""` when unwrapping fails? And try using `[String: Any]` instead of `NSDictionary` and check whether snapshot actually returns the value. – Jithin Aug 14 '20 at 08:50
  • The snapshot returns the value but only inside the function, when I call the var anywhere else than this function, it is = nil – James Caine Aug 14 '20 at 09:25
  • `var language: String = ""` is not an optional. You can never get its value as `nil`. If you are calling `getUserLanguage` in `viewDidLoad` and trying to access it before the completion is called, you will get an empty string. Can you add the snapshot value in question? – Jithin Aug 14 '20 at 09:31
  • I'm sorry but I don't understand what I am supposed to do, and the snapshot value is supposed to be "english" – James Caine Aug 14 '20 at 10:04
  • can you pls add the printed snapshot value in your question? – Jithin Aug 14 '20 at 10:20
  • I've modified the question – James Caine Aug 14 '20 at 10:27
  • The code in the question is incomplete as we don't know the order of your code execution. Printing self.language in viewDidLoad would print nothing unless that var was populated before printing, right? When is `getUserLanguage` called and where are there two lines with that same name? How do you know that the read node has a child 'language'? Please review the following guide [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). Update and clarify the question and we'll take a look. – Jay Aug 16 '20 at 14:42

2 Answers2

0
  1. Try to print languageResult in function - maybe you don't get it inside the function and the variable is not assigned
  2. Make language variable public
  • Making the var public doesn't change much. The function works and inside of it the right value is retrieved from Firebase, it is when I try to use the variable somewhere else that its value hasn't been updated – James Caine Aug 14 '20 at 12:05
0

I think you are missing the asynchronous nature of your code here. The getUserLanguage function will call the completion only when it gets callback from observe(.value, with: { (snapshot) method of firebase. It is asynchronous. You won't get the value of language right after you call getUserLanguage in viewDidLoad.

override func viewDidLoad() {
    super.viewDidLoad()
    
    getUserLanguage { (language) in
        print(language) // --> prints the expected value
        self.language = language
    }
    print(language) // --> prints ""
}

func getUserLanguage(completion: @escaping (String) -> Void) {
    let ref = Database.database().reference()
    let uid = Auth.auth().currentUser!.uid
    ref.child("users").child(uid).observe(.value, with: { (snapshot) in
        let value = snapshot.value as? [String: Any]

        let languageResult = value?["language"] as? String ?? ""
        print("language: ", languageResult) // --> prints the expected value

        completion(languageResult)
    })
}
Jithin
  • 913
  • 5
  • 6
  • How can I fix this then? I would like to be able to turn this value that I retrieve from Firebase with a snapshot into a variable – James Caine Aug 14 '20 at 12:01
  • You can use the variable `language` but its value will be set only after the completion closure is called in `getUserLanguage`. Pls check where I have set self.`language`. If you want to do something with it inside `viewDidLoad` itself, do it after that line. You can do whatever you want with that variable after that. – Jithin Aug 14 '20 at 12:07
  • Yes but for example the _print(language)_ just after _getUserLanguage_ is called in ViewDidLoad() returns empty, so I can't use the variable outside of _getUserLanguage_, why is the variable updated but only inside the function? – James Caine Aug 14 '20 at 12:34
  • Pls read this post: https://stackoverflow.com/a/46245943/5443937 and try to experiment with closures/completion handlers – Jithin Aug 14 '20 at 12:43
  • I'm sorry, I've read the article and tried to Implement it into my code but nothing seems to work, I don't know what to do about it anymore – James Caine Aug 15 '20 at 12:36