0

Hi I am a bit new to iOS development. I want to create a variable that store the UID = user.id from the firebase authentication check. Then I want to use that UID to put it in the url so that I can use that to call our backend. However, I couldn't figure out how to do it...

Xcode 11.6 swift 5

here is my swift code:

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        var UID = ""
        
        Auth.auth().addStateDidChangeListener { (auth, user) in
            if let user = user {
                self.userName.text = user.displayName
                //print(user.uid)
                UID = user.uid
            } else {
                self.userName.text = "error"
                
            }
        }
        
        
        self.navigationItem.setHidesBackButton(true, animated: true)

        
        //let url = vehicleManager.dataURL
        let url = rewardManager.dataURL
        print("UID is: \(UID)")
        rewardManager.performRequest(dataURL: url)
     
        claimWebKitView.load(URLRequest(url: URL(string: "https://camo.githubusercontent.com/6b254aa699df7f9464967009129c3017de721b77/68747470733a2f2f7261772e6769746875622e636f6d2f5068696c4a61792f4d50416e64726f696443686172742f6d61737465722f73637265656e73686f74732f7363617474657263686172742e706e67")!))
        premiumWebKitView.load(URLRequest(url: URL(string: "https://camo.githubusercontent.com/e29d8d3316203700965cc6cc56e67b779f2845bb/68747470733a2f2f7261772e6769746875622e636f6d2f5068696c4a61792f4d5043686172742f6d61737465722f73637265656e73686f74732f636f6d62696e65645f63686172742e706e67")!))
        
        
    }

debug console: enter image description here

how can I pass the user.uid to my url? thanks

XYD
  • 591
  • 1
  • 5
  • 9
  • That might be because of async operations try having a debug at `UID = user.uid` and check what you get back. – WhiteSpidy. Sep 26 '20 at 11:07
  • thanks. I have done that, if in Auth.auth().addStateDidChangeListener closure, I print out right after the UID = user.id. it actually works. But out side that closure it fails.... – XYD Sep 26 '20 at 11:37
  • Yes. That's because getting authentication status from firebase is an async operation and it takes some very minor time and in that duration the other written code gets executed. – WhiteSpidy. Sep 26 '20 at 11:40
  • For clarity, the code following the firebase closure, like this `self.navigationItem...` will happen before the code within the closure. You have to wait for firebase to return data before operating on it - that data is only valid *within* the closure. – Jay Sep 27 '20 at 13:35

2 Answers2

1

The reason why you are not getting any value in UID while printing is because the auth.addStateChangedListener is an async operation that is it takes some time to get your data from firebase and in that time duration your other code gets executed first. I would suggest to use completion handlers for these type of async operations. Here is the link of S.O question from where you can get more details about completion handlers.

Quick Overview :- Your completion handler gets called when the function has completed it's execution and at that part you can do your api calls by checking if you have received the correct userId or not.

WhiteSpidy.
  • 1,107
  • 1
  • 6
  • 28
  • Thanks App Dev, I think you are definitely right, completion handler must be the right way to go. I have tried to build it, but it didn't give me the right output still, I edited my question, could you please take a look again? Thanks for your help! – XYD Sep 27 '20 at 13:49
  • Hey @Yudi. Great it did help you your newly updated question is completely different now. It is because you haven't written your completion handler properly. Please have a look at this answer it explains some what better https://stackoverflow.com/a/41539063/12768366. If you still face any issues please post a different question about it (as this issue is different then what you faced before) and let me know I would be happy to help. – WhiteSpidy. Sep 27 '20 at 16:10
  • I think I fixed it myself ;-) finally... after hours of work... – XYD Sep 27 '20 at 16:19
0

after the great help from @Dev App and others, I finally figured it out I think.

So the key is to call my API in side this Firebase authentication method

    func getUserName() {
        Auth.auth().addStateDidChangeListener { (auth, user) in
            if let user = user {
                self.userName.text = user.displayName
                
            } else {
                self.userName.text = "error"
                
            }
        }
    }

any data in that closure, such as user.displayname or user.uid is only valid in that closure.

So, I added my callApi function into that firebase authentication function. Something like below solves the problem.

func callApiFunction() {
    //some code to call the api
}


func firebaseAuth() {
     // some code to do authentication, and get back some data, for example:
       func getUserName() {
        Auth.auth().addStateDidChangeListener { (auth, user) in
            if let user = user {
                self.userName.text = user.uid
                // you can pass the uid here to the callApiFunction()
                callApiFunction()
            } else {
                self.userName.text = "error"
                
            }
        }
    }

}


then you can call the func firebaseAuth() in other places, like viewdidLoad() etc.

override func viewDidLoad() {
   firebaseAuth()

}

XYD
  • 591
  • 1
  • 5
  • 9