【问题标题】:How to read correctly the database of Firebase on the viewDidLoad() func?如何在 viewDidLoad() 函数上正确读取 Firebase 的数据库?
【发布时间】:2018-01-24 14:24:30
【问题描述】:
//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)
    }
}

控制台:

 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))

问题很简单。有人可以解释一下"print("viewDidLoad user:....")" 怎么可能在“验证用户调用”和“用户”之间打印出数据库信息?

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

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

out:

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

所以……这就是问题

谢谢!

为 Anas Menhar 编辑 这是我的结构。为什么成为 NSObject 会更好? 我做了一个 Struct 因为我可以做两个不同的初始化(一个是空的),而 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

}
}

为 Hitesh 编辑

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

【问题讨论】:

  • 您打印了let dictionary = snapshot.value 吗?你可以添加这个吗?
  • 向我展示你的 AppUser 模式类,它必须类似于 class User: NSObject { var id: String?变量名称:字符串? var 电子邮件:字符串? var imageURL:字符串?并且也使用这一行 user.setValuesForKeys(dictionary)

标签: swift firebase firebase-realtime-database


【解决方案1】:

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

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

  1. super.viewDidLoad()
  2. verifyUser() 被调用
  3. 打印verifyUser() 中的语句
  4. verifyUser() 中的保护语句
  5. viewDidLoad() 中打印声明
  6. super.viewDidAppear()
  7. 打印在super.viewDidAppear()

.observeSingleEventOf 闭包中的所有内容都将在 4 之后的某个时间点发生——只要该调用完成。如果你想在调用结束时做一些事情,把它放在闭包中。

像这样:

 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)
}

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

旁注:如果您要为 AppUser 使用 Struct,请确保您了解结构和类之间的区别。您可以有一个名为 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

【讨论】:

  • 上课有哪些优点?结构是值类型和类是引用类型的主要区别不是吗?所以在我的情况下,结构会做得更好,不是吗?最后一件事,为什么在其余的 viewDidLoad 代码之后会出现网络问题?谢谢!!
  • 是的,没错。作为引用类型的类使它们稍后随着您的功能扩展而更具动态性。网络调用按您编写它们的顺序开始,但它们不一定按该顺序完成。想象一下,您正在下载一张 10mb 的高分辨率照片和一张 500kb 的低分辨率照片。您可以按任何顺序启动它们,但是(除非它们同步运行)500kb 可能会先完成。
猜你喜欢
  • 2021-02-16
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
  • 2020-03-11
  • 1970-01-01
相关资源
最近更新 更多