视图模型中的 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 方法中调用的主要内容,如果未能解决你的问题,请参考以下文章