Getting variable outside scope?

Hi,


First off; I know this is probably elementary stuff, and I´m taking courses to learn Swift, but I have a project on the side that I´m having a issue with:


I want to read data from Firebase Database, and post it back in a different node in the same Database. I have managed to get the data from the Database, but the constant isn´t reachable outside the scope.

This is the code I´m using:


override func viewDidLoad() {
        super.viewDidLoad()
     
        ref = Database.database().reference()
        let user = Auth.auth().currentUser!.uid
     
        //Read data from Firebase
     
       ref?.child("users").child(user).observeSingleEvent(of: .value, with: { (snapshot) in
     
            guard let userDict = snapshot.value as? [String: Any],
                let address = userDict["Address"] as? String,
                let name = userDict["Name"] as? String else {
                    return
             
            }
     
     
         
            print(address + name)
     
     
        })
     
    }


How do I need to go about to get the address and name constant?

Help with this is greatly appreciated

What do you want to read outside:

- address and name ?


Do you want to read it inside the same controller where you have viewDidLoad ?


If so, simply declare var in this controller :


class myController : .....
     private var address : String = ""     // You could also initialize with "unknown address"
     private var name : String = ""         // You could also initialize with "unknow"

Get them in the closure (need to say self.name and self.address) :


            guard let userDict = snapshot.value as? [String: Any],
                self.address = userDict["Address"] as? String
                self.name = userDict["Name"] as? String else {
                    return
 }

Then you can reuse elsewhere in the controller.

If you need to read in another class, you can simply define it before the class declaration

    var address : String = ""     // You could also initialize with "unknown address"
    var name : String = ""         // You could also initialize with "unknow"
class myController : .....

Thank you for you quick response! 🙂


X-code didn´t like the self declaration. Autocorrect wants me do do this:


ref?.child("users").child(user).observeSingleEvent(of: .value, with: { (snapshot) in
       
            guard let userDict = snapshot.value as? [String: Any],
                self.address == (userDict["Address"] as? String)!,
                self.name == (userDict["Name"] as? String)! else {
                    return
               
            }
       
       
       
            print(self.address + self.name)
       
       
        })


The variables name and address isn´t returning anything with this.

You write


self.address == (userDict["Address"] as? String)!,

Thjis is not = (for assignment) but == (which tests for equality)


in fact, I was a bit too fast in my reply, you shoud do this, to avoid possible crashes:


            guard let userDict = snapshot.value as? [String: Any] else { return }

            self.address = userDict["Address"] as? String ?? "No address"
            self.name = userDict["Name"] as? String ?? "No name"

I´m sorry, i expressed myself poorly.


When I use:

self.address = (userDict["Address"] as? String)!,

X-code complains of: use of '=' in a boolean context, did you mean '=='?


Thank youfor your patience

Accepted Answer

You can't unwrap the optional without a "let", so this syntax doesn't work.


You should go back to your original code. After the entire guard statement, you can assign the now-unwrapped values to your instance properties:


            guard let userDict = snapshot.value as? [String: Any], 
                let address = userDict["Address"] as? String, 
                let name = userDict["Name"] as? String else { 
                    return 
            }
            self.address = address
            self.name = name


Note that your guard statement introduced two names that "shadow" the instance properties, but you can disambiguate by the presence or absence of "self.", as in lines 5-6.


Having said that, the compiler might think you mean the instance properties on the RHS of those two assignments and suggest inserting "self." there too. In that case, you should change the names of the "let" variables to something else, e.g. "knownAddress" and "knownName". Or do that anyway, if the shadowing is just confusing regardless.

Does compiler complain if you write exactly this ? (tested in Swift 2)


            guard let userDict = snapshot.value as? [String: Any] else { return } 
 
            self.address = userDict["Address"] as? String ?? "No address" 
            self.name = userDict["Name"] as? String ?? "No name"

Yes!

That worked perfectly! Thanks alot!

Getting variable outside scope?
 
 
Q