视图模型中的 Firestore 方法未在 SwiftUI onAppear 方法中调用

Posted

技术标签:

【中文标题】视图模型中的 Firestore 方法未在 SwiftUI onAppear 方法中调用【英文标题】:Firestore method in view model not invoking in SwiftUI onAppear method 【发布时间】:2021-04-23 21:11:15 【问题描述】:

我想实现一个文本字段来显示当前用户在数据库(Firestore)中的现有分数。由于 Firebase 查询中异步的性质,我还需要对我的代码进行一些调整。但是,completion() 处理程序似乎无法正常工作:

// ViewModel.swift

import Foundation
import Firebase
import FirebaseFirestore

class UserViewModel: ObservableObject 
    let current_user_id = Auth.auth().currentUser!.uid
    private var db = Firestore.firestore()
    @Published var xp:Int?
    
    func fetchData(completion: @escaping () -> Void) 
        let docRef = db.collection("users").document(current_user_id)
        
        docRef.getDocument  snapshot, error in
              print(error ?? "No error.")
              self.xp = 0
              guard let snapshot = snapshot else 
                  completion()
                  return
              
            self.xp = (snapshot.data()!["xp"] as! Int)
            completion()
        
    

// View.swift

import SwiftUI
import CoreData
import Firebase


    @ObservedObject private var users = UserViewModel()
    var body: some View 
        VStack 
            HStack 
                // ...
                Text("xp: \(users.xp ?? 0)")
//                    Text("xp: 1500")
                    .fontWeight(.bold)
                    .padding(.horizontal)
                    .foregroundColor(Color.white)
                    .background(Color("Black"))
                    .clipShape(CustomCorner(corners: [.bottomLeft, .bottomRight, .topRight, .topLeft], size: 3))
                    .padding(.trailing)
            
            .padding(.top)
            .onAppear() 
                self.users.fetchData()
            
// ...
    

我的结果在Text("xp: \(users.xp ?? 0)") 中一直显示为 0,这表示该步骤尚未异步。那我该怎么解决呢?

【问题讨论】:

您没有显示fetchData 的调用位置。另外,您确定self.xp 被分配了吗?您是否设置了断点或打印语句以确保获得您期望的值? 在这种情况下完成处理程序应该做什么也不是很清楚。您的视图将自动响应 @Published 属性,进一步强化了代码实际上可能没有成功到达或分配 self.xp 的想法 好吧,我只是相信因为 Firebase 总是异步检索数据,completion() 处理程序有助于指示此步骤需要在任何其他步骤之前完成。你的意思是completion()在这里没用吗? 您在编辑中添加的调用站点似乎甚至无效(它没有为完成处理程序提供参数。所以,是的,出于这个原因和我上面说了,这里好像没啥用。 【参考方案1】:

在进一步调试之前,我会先检查以确保 Firestore 控制台中的数据有效。也就是说,如果您使用可观察对象,则可以取消完成处理程序,并且应该安全地解包数据。错误总是可以通过网络调用发生,所以总是安全地解开遇到的任何东西。此外,利用 Firestore API 中惯用的 get() 方法,它使代码更易于阅读。

也就是说,问题在于您在水平堆栈的onAppear 方法中手动获取数据的调用。这种模式可能会在 SwiftUI 中产生令人讨厌的结果,因此只需删除在视图中手动获取数据的调用,并在视图模型的初始化程序中自动执行。

class UserViewModel: ObservableObject 
    @Published var xp: Int?
    
    init() 
        guard let uid = Auth.auth().currentUser?.uid else 
            return
        
        let docRef = Firestore.firestore().collection("users").document(uid)

        docRef.getDocument  (snapshot, error) in
            if let doc = snapshot,
               let xp = doc.get("xp") as? Int 
                self.xp = xp
             else if let error = error 
                print(error)
            
        
    


struct ContentView: View 
    @ObservedObject var users = UserViewModel()

    var body: some View 
        VStack 
            HStack 
                Text("xp: \(users.xp ?? 0)")
            
        
    

SwiftUI View - viewDidLoad()? 是你最终要解决的问题。

【讨论】:

老实说,我看不出你的答案和我的有什么区别。更不用说您使用guard let 的声明是非法的。 那你有数据问题、网络问题或授权问题,所以从列表中删除代码并继续调试。 对谁不合法? 确保currentUser? 是可选的链式,而不是像你拥有的那样强制解包:guard let uid = Auth.auth().currentUser?.uid 阅读接受的答案中最受好评的评论,您将看到最终需要在哪里解决问题,找到正确的位置来调用获取数据的调用(如果初始化程序不在您的位置想做)。 ***.com/questions/56496359/swiftui-view-viewdidload

以上是关于视图模型中的 Firestore 方法未在 SwiftUI onAppear 方法中调用的主要内容,如果未能解决你的问题,请参考以下文章

React setState未在firestore中执行添加文档承诺解析

引导日期选择器未在 editorFor 中显示模型值

ListBoxFor 未在提交时完全更新视图模型

ko 视图模型在 js 上更新但未在 html 视图中显示

SwiftUI ChildView 未在状态更改时重新计算

DAE 模型未在 iOS 应用程序中显示应用的纹理