如何在viewDidLoad()函数上正确读取Firebase数据库?

时间:2022-10-29 13:06:18
//Just a struct to save information about the User
var user = AppUser()

override func viewDidLoad() {
    super.viewDidLoad()

 //Verify if user is logged in
    verifyUser()
    user.email = "blabla"

    print("viewdidload user: \(user)")

}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(true)

    print("viewdidappear user: \(user)")

} 

func verifyUser() {

    print("verify user called")

    //Log in verification
    guard let userID = Auth.auth().currentUser?.uid else {
        perform(#selector(handleLogOut), with: nil, afterDelay: 0)

        print("nil user")

        return
    }

    ref.child("users").child(userID).observeSingleEvent(of: .value, with: { (snapshot) in
        if let dictionary = snapshot.value as? [String: AnyObject] {
            self.user = AppUser(dictionary: dictionary)

            print(self.user)
        }
    }) { (error) in
        print(error.localizedDescription)
    }
}

Console:

安慰:

 verify user called


 viewdidload user: AppUser(id: nil, name: nil, email: 
 Optional("blabla"), completedRegister: nil, FULLUser: nil)


 viewdidappear user: AppUser(id: nil, name: nil, email:                
 Optional("blabla"), completedRegister: nil, FULLUser: nil)


 AppUser(id: nil, name: nil, email: Optional("x@gmail.com"),      
 completedRegister: Optional(false), FULLUser: Optional(false))

The question is simple. Can someone explain how is it possible that "print("viewDidLoad user:....")" is printed between "verify user called" and "the user" with the database information?

问题很简单。有人可以解释一下“打印(”viewDidLoad user:....“)”是如何在“验证用户调用”和“用户”之间打印数据库信息的?

The problem is when I try to get information of the user on the viewDidLoad the function for some reason hasn't get the information so the values are still nil. Is it a question of time?

问题是当我尝试在viewDidLoad上获取用户的信息时,由于某种原因,该函数没有获取信息,因此值仍为零。这是时间问题吗?

I tried to put a loop after the function verifyUser() but it never gets

我试图在函数verifyUser()之后放置一个循环,但它永远不会得到

out:

    while user.email == nil {
            print("Waiting...")
        }

So... thats the question

所以...这就是问题所在

Thanks!

谢谢!

edit for Anas Menhar This is my struct. Why would it be better to be a NSObject? I did a Struct because I could do two different inits (one empty) and the NsObject didn't let me for some reason

编辑Anas Menhar这是我的结构。为什么成为NSObject会更好?我做了一个Struct,因为我可以做两个不同的inits(一个空)和NsObject由于某种原因没有让我

struct AppUser {
var id: String?
var name: String?
var email: String?

var completedRegister: Bool?

var FULLUser: Bool?

init(dictionary: [String: Any]) {
    self.id = dictionary["id"] as? String
    self.name = dictionary["name"] as? String
    self.email = dictionary["email"] as? String

    self.completedRegister = Bool((dictionary["completedRegister"] as? String)!)

    self.FULLUser = Bool((dictionary["FULLUser"] as? String)!)

}
init() {
    self.id = nil
    self.name = nil
    self.email = nil

    self.completedRegister = nil

    self.FULLUser = nil

}
}

edit for Hitesh

为Hitesh编辑

if I print the dictionary it prints just at the same time that the user completed with the information. At the end of everything.

如果我打印字典,它就会在用户完成信息的同时打印。一切都结束了。

1 个解决方案

#1


1  

The issue is that viewDidLoad() calls verifyUser() before printing "viewdidload user: \(user)". Everything in verifyUser() will finish (with exception to your network call) before the print.

问题是viewDidLoad()在打印“viewdidload user:\(user)”之前调用verifyUser()。在打印之前,verifyUser()中的所有内容都将完成(网络调用除外)。

So here is the sequence of events happening for you:

所以这是发生在你身上的一系列事件:

  1. super.viewDidLoad()
  2. super.viewDidLoad()
  3. verifyUser() is called
  4. 调用verifyUser()
  5. print statement that is in verifyUser()
  6. 在verifyUser()中的print语句
  7. guard statement that is in verifyUser()
  8. 在verifyUser()中的guard语句
  9. print statement in viewDidLoad()
  10. viewDidLoad()中的print语句
  11. super.viewDidAppear()
  12. super.viewDidAppear()
  13. print in super.viewDidAppear()
  14. 在super.viewDidAppear()中打印

Everything inside the closure for the .observeSingleEventOf will happen some point after 4 -- whenever that call finishes. If you want to do something when the call is finished, put it in the closure.

关闭.observeSingleEventOf的闭包内的所有内容都将在4之后的某个时刻发生 - 每当调用结束时。如果您想在呼叫结束时执行某些操作,请将其放入闭包中。

Like this:

喜欢这个:

 ref.child("users").child(userID).observeSingleEvent(of: .value, with: { (snapshot) in
    if let dictionary = snapshot.value as? [String: AnyObject] {
        self.user = AppUser(dictionary: dictionary)
        //***handle stuff that needs the user here
        print(self.user)
    } else {
        //***handle getting no data for the user or data that is not [String: AnyObject]
    }
}) { (error) in
    //***handle any errors here
    print(error.localizedDescription)
}

The places where I added comments are the places that would potentially be called when that request completes.

我添加注释的位置是该请求完成时可能会调用的位置。

Side note: If you are going to use a Struct for AppUser, just make sure you know the differences between structs and classes. You could have a class named AppUser and have two different inits like this:

附注:如果您打算使用Struct for AppUser,只需确保您知道结构和类之间的差异。你可以有一个名为AppUser的类,它有两个不同的命令,如下所示:

class AppUser {
    var id: String?
    var name: String?
    var email: String?
    var completedRegister: Bool?
    var FULLUser: Bool?

    ///initialization from a dictionary
    init(dictionary: [String: Any]) {
        id = dictionary["id"] as? String
        name = dictionary["name"] as? String
        email = dictionary["email"] as? String

        if let completed = dictionary["completedRegister"] as? String {
            if completed == "true" {
                completedRegister = true
            } else if completed == "false" {
                completedRegister = false
            }
        }

        if let fullUser = dictionary["FULLUser"] as? String {
            if fullUser == "true" {
                FULLUser = true
            } else if fullUser == "false" {
                FULLUser = false
            }
        }
    }

    ///initialization without a dictionary
    init() {
        //dont need to set any variables because they are optional
    }
 }

let user1 = AppUser(dictionary: ["id": "12342",
                             "name": "John Doe",
                             "email": "email@email.com",
                             "completedRegister": "true",
                             "FULLUser": "true"])
    ///user1 properties:
    id: Optional("12342")
    - some: "12342"
    name: Optional("John Doe")
    - some: "John Doe"
    email: Optional("email@email.com")
    - some: "email@email.com"
    completedRegister: Optional(true)
    - some: true
    FULLUser: Optional(true)
    - some: true

let user2 = AppUser()
///user2 properties: none

#1


1  

The issue is that viewDidLoad() calls verifyUser() before printing "viewdidload user: \(user)". Everything in verifyUser() will finish (with exception to your network call) before the print.

问题是viewDidLoad()在打印“viewdidload user:\(user)”之前调用verifyUser()。在打印之前,verifyUser()中的所有内容都将完成(网络调用除外)。

So here is the sequence of events happening for you:

所以这是发生在你身上的一系列事件:

  1. super.viewDidLoad()
  2. super.viewDidLoad()
  3. verifyUser() is called
  4. 调用verifyUser()
  5. print statement that is in verifyUser()
  6. 在verifyUser()中的print语句
  7. guard statement that is in verifyUser()
  8. 在verifyUser()中的guard语句
  9. print statement in viewDidLoad()
  10. viewDidLoad()中的print语句
  11. super.viewDidAppear()
  12. super.viewDidAppear()
  13. print in super.viewDidAppear()
  14. 在super.viewDidAppear()中打印

Everything inside the closure for the .observeSingleEventOf will happen some point after 4 -- whenever that call finishes. If you want to do something when the call is finished, put it in the closure.

关闭.observeSingleEventOf的闭包内的所有内容都将在4之后的某个时刻发生 - 每当调用结束时。如果您想在呼叫结束时执行某些操作,请将其放入闭包中。

Like this:

喜欢这个:

 ref.child("users").child(userID).observeSingleEvent(of: .value, with: { (snapshot) in
    if let dictionary = snapshot.value as? [String: AnyObject] {
        self.user = AppUser(dictionary: dictionary)
        //***handle stuff that needs the user here
        print(self.user)
    } else {
        //***handle getting no data for the user or data that is not [String: AnyObject]
    }
}) { (error) in
    //***handle any errors here
    print(error.localizedDescription)
}

The places where I added comments are the places that would potentially be called when that request completes.

我添加注释的位置是该请求完成时可能会调用的位置。

Side note: If you are going to use a Struct for AppUser, just make sure you know the differences between structs and classes. You could have a class named AppUser and have two different inits like this:

附注:如果您打算使用Struct for AppUser,只需确保您知道结构和类之间的差异。你可以有一个名为AppUser的类,它有两个不同的命令,如下所示:

class AppUser {
    var id: String?
    var name: String?
    var email: String?
    var completedRegister: Bool?
    var FULLUser: Bool?

    ///initialization from a dictionary
    init(dictionary: [String: Any]) {
        id = dictionary["id"] as? String
        name = dictionary["name"] as? String
        email = dictionary["email"] as? String

        if let completed = dictionary["completedRegister"] as? String {
            if completed == "true" {
                completedRegister = true
            } else if completed == "false" {
                completedRegister = false
            }
        }

        if let fullUser = dictionary["FULLUser"] as? String {
            if fullUser == "true" {
                FULLUser = true
            } else if fullUser == "false" {
                FULLUser = false
            }
        }
    }

    ///initialization without a dictionary
    init() {
        //dont need to set any variables because they are optional
    }
 }

let user1 = AppUser(dictionary: ["id": "12342",
                             "name": "John Doe",
                             "email": "email@email.com",
                             "completedRegister": "true",
                             "FULLUser": "true"])
    ///user1 properties:
    id: Optional("12342")
    - some: "12342"
    name: Optional("John Doe")
    - some: "John Doe"
    email: Optional("email@email.com")
    - some: "email@email.com"
    completedRegister: Optional(true)
    - some: true
    FULLUser: Optional(true)
    - some: true

let user2 = AppUser()
///user2 properties: none