ios - SwiftUI Lists + Firebase Firestore,获取数据然后取消获取?(漏洞)
问题描述
我不确定我的项目有什么问题。基本上,我有一个非常典型的数据结构:我将 Firestore 用于基于实时文档的数据库,并且我有一堆不同的集合、文档和字段。非常简单,没有什么疯狂的。
我有一些模型类,然后是一些 ViewModel 来获取数据、过滤、将文档添加到 Firestore 等等。
该应用程序本身几乎是 100% 的 SwiftUI,我希望保持这种状态,这对我自己的开发来说只是一个挑战。不过,我已经碰壁了。
在应用程序中,我有一系列带有 NavigationView 列表的视图,我在您导航时将小块数据传递给这些视图。一个示例(这是针对教育机构的)可能是学校列表 > 班级列表 > 班级学生列表 > 学生成绩列表。基本上是导航视图和一堆列表的完美用途。
错误:当我从堆栈中的一个列表移动到下一个列表时,我获取了 Firestore 数据,该数据加载了一秒钟(足以填充列表),然后“卸载”回无。这是发生这种情况的一些代码(我已经对其进行了清理以使其尽可能简单):
struct ClassListView: View {
let schoolCode2: String
let schoolName2: String
@ObservedObject private var viewModelThree = ClassViewModel()
var body: some View {
VStack{
List{
if viewModelThree.classes.count > 0{
ForEach(self.viewModelThree.classes) { ownedClass in
NavigationLink(destination: StudentListView()){
Text(ownedClass.className)
}
}
} else {
Text("No Classes Found for \(schoolName2)")
}
}
}
.navigationBarTitle(schoolName2)
.onAppear(){
print("appeared")
self.viewModelThree.fetchData(self.schoolCode2)
}
}
}
这就是我一直遇到问题的 ClassListView。为了调试,我添加了 else Text("No Classes Found") 行,它确实显示了。所以基本上,视图加载(这一切都在来自父级的导航视图中),它获取数据,显示一秒钟(列表填充),然后出于某种原因卸载该数据,只留下“没有类成立”。
有关更多上下文,这是 ClassViewModel 的代码(也许这就是我要出错的地方?):
struct Classes: Identifiable, Codable {
@DocumentID var id: String? = UUID().uuidString
var schoolCode: String
var className: String
}
enum ClassesCodingKeys: String, CodingKey {
case id
case schoolCode
case className
}
class ClassViewModel: ObservableObject {
@Published var classes = [Classes]()
private var db = Firestore.firestore()
func fetchData(_ schoolCode: String) {
db.collection("testClasses")
.order(by: "className")
.whereField("schoolCode", isEqualTo: schoolCode)
.addSnapshotListener{ (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("no docs found")
return
}
self.classes = documents.compactMap{ queryDocumentSnapshot -> Classes? in
return try? queryDocumentSnapshot.data(as: Classes.self)
}
}
}
func addClass(currentClass: Classes){
do {
let _ = try db.collection("testClasses").addDocument(from: currentClass)
}
catch {
print(error)
}
}
}
最相关的位是上面的 fetchData() 函数。
也许问题出在此之前的视图中(父视图?)。这里是:
struct SchoolUserListView: View {
@State private var userId: String?
@EnvironmentObject var session: SessionStore
@ObservedObject private var viewModel = UserTeacherViewModel()
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State private var counter = 0
@State private var showingAddSchool: Bool = false
@Environment(\.presentationMode) var presentationMode
func getUser() {
session.listen()
}
var body: some View {
VStack{
List{
if viewModel.teachers.count > 0{
ForEach(viewModel.teachers) { ownedClass in
NavigationLink(destination: ClassListView(schoolName2: ownedClass.schoolName, schoolCode2: ownedClass.schoolCode)){
Text(ownedClass.schoolName)
}
}
} else {
Button(action:{
self.presentationMode.wrappedValue.dismiss()
}){
Text("You have no schools, why not add one?")
}
}
}
.navigationBarTitle("Your Schools")
}
.onAppear(){
self.getUser()
self.userId = self.session.session?.uid
}
.onReceive(timer){ time in
if self.counter == 1 {
self.timer.upstream.connect().cancel()
} else {
print("fetching")
self.viewModel.fetchData(self.userId!)
}
self.counter += 1
}
}
}
以及该视图的 FURTHER 父级(实际上是应用程序的起始视图):
struct StartingView: View {
@EnvironmentObject var session: SessionStore
func getUser() {
session.listen()
}
var body: some View {
NavigationView{
VStack{
Text("Welcome!")
Text("Select an option below")
Group{
NavigationLink(destination:
SchoolUserListView()
){
Text("Your Schools")
}
NavigationLink(destination:
SchoolCodeAddView()
){
Text("Add a School")
}
Spacer()
Button(action:{
self.session.signOut()
}){
Text("Sign Out")
}
}
}
}
.onAppear(){
self.getUser()
}
}
}
我知道这很多,但是每个人都有父母的顺序:
StartingView > SchoolUserListView > ClassListView(此处出现BUG)
顺便说一句,SchoolUserListView 使用 fetchData 方法,就像 ClassListView(错误所在)一样,并将其输出到 foreach 列表,同样的事情,但没有问题?我只是不确定问题是什么,非常感谢任何帮助!
这是该问题的视频: https ://imgur.com/a/kYtow6G
解决方案
解决它!问题是在导航视图中传递了用于演示模式的 EnvironmentObject。这似乎会导致很多不良行为。小心传递presentationMode,因为它似乎会导致数据重新加载(因为它正在更新)。
推荐阅读
- xaml - UWP NavigationView 移除转场动画
- javascript - 单击按钮时如何调用此函数?(Javascript、XSLT、XML、HTML)
- json - 仅将 JSON 数组中的日期格式化为时间
- java - Selenium WebDriver.get() 在加载的页面为空并带有警报弹出登录时卡住
- r - 为主体中 dplyr 参数的函数提供多组变量
- python - 我无法安装 Tkinter 或 tkinter。我尝试了所有代码并重新安装了 TCL/TK。但是还是报错
- jenkins - 如何在 Perforce 和 Jenkins 中使用带有自定义视图映射的流
- nhibernate - Fluent Nhibernate 将集合映射到通用实体
- java - 使用不同的 JRE 运行 Java 程序?
- android - TabLayout 中的 ListView 下方未显示按钮