我该如何从闭包中拉出该值以更新Swift中的cutom对象? [英] How do I pull this value out of a closure to update a cutom Object in Swift?

查看:89
本文介绍了我该如何从闭包中拉出该值以更新Swift中的cutom对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个具有Firestore后端的应用程序,并且试图使用当前用户的设置页面信息来调用文档。更新空数组时,我能够做到这一点没有问题,但是尝试填充单个文档的时间很糟糕。我有一个名为 DxUser 的自定义对象:

  struct DxUser {
var email:String?
var名称:String?
var timeStamp:日期?
var profileImageURL:String?
var ehr:字符串?

var字典:[String:Any]? {
return [
email:email,
name:name,
timeStamp:timeStamp,
profileImageURL:profileImageURL,
ehr:作为任何

]
}
}


扩展名的DxUser:DocumentSerializable {
init? (字典:[String:Any]){
警卫让email = dictionary [ email]为?字符串,
让name = dictionary [ name]为?字符串,
让timeStamp = dictionary [ timeStamp]为?日期,
让profileImageURL = dictionary [ profileImageURL]为?字符串,
让ehr = dictionary [ ehr]为?字符串else {return nil}

self.init(电子邮件:电子邮件,名称:名称,timeStamp:timeStamp,profileImageURL:profileImageURL,ehr:ehr)
}
}

在视图控制器中,我试图用当前用户更新此变量,但我只能抓住它在闭包中,并且在块外的任何地方填充为nil。这是我正在使用的基本代码,但是谁能告诉我我缺少什么?

  class SettingsController:UIViewController {

var dxUser = DxUser()


覆盖func viewDidLoad(){
super.viewDidLoad()
fetchUser()
}

func fetchUser(){

Guard let uid = Auth.auth()。currentUser?.uid else {
return
}

let userRef = db.collection( users)。document(uid)

userRef.getDocument {{document,error)in
if error!= nil {
打印(任何错误)
}否则{
self.dxUser = DxUser(dictionary:(document?.data())!)!
self.navigationItem.title = self.dxUser.name
打印(self.dxUser)
}
}
}
  db.collection( users)。document(uid!)。collection( goals)。getDocuments {(快照,错误)在
中,如果错误!= nil {
print(error as Any)
} else {
//将配置文件数组设置为等于我在$ b以下查询的内容$ b GoalArray = snapshot!.documents.flatMap({Goal(dictionary:$ 0.data())})
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
}
}


解决方案

与访问dxUser的位置 无关。这是 timing 。 Firebase API是异步的,这意味着 userRef.getDocument()立即返回,并且仅在请求完成后才收到回调。如果您尝试在 fetchUser()方法内的调用之后立即访问 dxUser ,则它将不可用,因为请求未完成。鉴于异步API的工作方式,您应仅在调用回调后使用 dxUser ,这通常意味着延迟在应用程序中呈现数据(例如您的打印对帐单所在的位置)。



请在此处阅读更多有关Firebase API为何异步以及对它们的期望。


I am building am application with a Firestore back end, and I am trying to call a document down with the current user's info for their settings page. I am able to do this no problems when updating an empty array, but am having a terrible time trying to populate a single document. I have a custom object called DxUser:

struct DxUser {
    var email:String?
    var name:String?
    var timeStamp:Date?
    var profileImageURL:String?
    var ehr: String?

    var dictionary:[String:Any]? {
        return [
            "email":email,
            "name":name,
            "timeStamp":timeStamp,
            "profileImageURL":profileImageURL,
            "ehr": ehr as Any

        ]
    }
}


extension DxUser : DocumentSerializable {
    init?(dictionary: [String : Any]) {
        guard let email = dictionary["email"] as? String,
            let name = dictionary["name"] as? String,
            let timeStamp = dictionary["timeStamp"] as? Date,
            let profileImageURL = dictionary["profileImageURL"] as? String,
            let ehr = dictionary["ehr"] as? String else {return nil}

        self.init(email: email, name: name, timeStamp: timeStamp, profileImageURL: profileImageURL, ehr: ehr)
    }
}

In the view controller, I am trying to update this variable with the current user, but I can only grab it in the closure, and it populates as nil anywhere outside the block. Here is the basic code I am using, but can anyone tell me what I am missing?

class SettingsController: UIViewController {

var dxUser = DxUser()


override func viewDidLoad() {
    super.viewDidLoad() 
    fetchUser()
}

func fetchUser() {

    guard let uid = Auth.auth().currentUser?.uid else {
        return
    }

    let userRef = db.collection("users").document(uid)

    userRef.getDocument { (document, error) in
        if error != nil {
            print(error as Any)
        } else {
            self.dxUser = DxUser(dictionary: (document?.data())!)!
            self.navigationItem.title = self.dxUser.name
            print (self.dxUser)
        }
    }
}

Yeah, this is how I am doing it on the table view, but I didn't see anything comparable on the regular VC.

db.collection("users").document(uid!).collection("goals").getDocuments { (snapshot, error) in
        if error != nil {
            print(error as Any)
        } else {
            //set the profile array to equal whatever I am querying below
            goalsArray = snapshot!.documents.flatMap({Goal(dictionary: $0.data())})
            DispatchQueue.main.async {
                self.collectionView?.reloadData()
            }
        }
    }

解决方案

It's not so much about the location of where you can access dxUser. It's the timing. Firebase APIs are asynchronous, which means userRef.getDocument() returns immediately, and you receive a callback only after the request completes. If you try to access dxUser right after that call within your fetchUser() method, it will not be available, because the request isn't complete. Given that's how async APIs work, you should only work with dxUser after the callback invoked, which usually means delaying the rendering of that data in your app (such as where your print statement is).

Please read more here about why Firebase APIs are asynchronous and what you can expect from them.

这篇关于我该如何从闭包中拉出该值以更新Swift中的cutom对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆