How do I pull this value out of a closure to update a cutom Object in Swift?

我只是一个虾纸丫 提交于 2019-12-13 03:55:46

问题


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

回答1:


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.




回答2:


I actually figured it out. I pulled the fetchUser() function out to the viewWillAppear function so I called it before the view appeared. Then I did the async function to re-run viewDidLoad. Anyone else have any better suggestions?

    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(true)
      fetchUser()
    }

    func fetchUser() {

      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())!)!            
              DispatchQueue.main.async {
                  self.viewDidLoad()
              }     
              self.navigationItem.title = self.dxUser.name
          }
      }
  }


来源:https://stackoverflow.com/questions/48875822/how-do-i-pull-this-value-out-of-a-closure-to-update-a-cutom-object-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!