我正在使用Firestore后端构建AM应用程序,我试图将文档拨打,并使用当前用户的设置页面上的信息来调整文档。在更新空数组时,我可以做到这一点,但是尝试填充单个文档的时间很糟糕。我有一个称为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)
}
}
在视图控制器中,我试图与当前用户更新此变量,但是我只能在闭合中抓住它,并且它在块外的任何地方都填充了零。这是我正在使用的基本代码,但是谁能告诉我我缺少什么?
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)
}
}
}
是的,这就是我在表观上进行操作的方式,但是我在常规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()
}
}
}
与您可以访问dxuser的位置不多。这是时间。Firebase API是异步的,这意味着userRef.getDocument()
立即返回,并且您仅在请求完成后才收到回调。如果您尝试在fetchUser()
方法中访问该呼叫后立即访问dxUser
,则它将无法使用,因为请求尚未完成。鉴于ASYNC API的工作方式,您应仅使用dxUser
调用回调,这通常意味着延迟应用程序中该数据的渲染(例如打印语句的位置(。
请在这里阅读更多有关为什么Firebase API异步以及您对它们的期望的信息。
我实际上弄清楚了。我将fetchuser((函数拉出到viewwillappear函数,所以在视图出现之前,我将其调用。然后,我执行了异步函数以重新运行ViewDidload。其他人有更好的建议?
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
}
}
}