Списки SwiftUI + Firebase Firestore, получение данных, а затем извлечение? (Ошибка)
Я не уверен, в чем проблема с моим проектом. По сути, у меня довольно типичная структура данных: я использую Firestore для базы данных на основе документов в реальном времени, и у меня есть множество разных коллекций, документов и полей. Просто очень просто, ничего безумного.
У меня есть несколько классов моделей, а затем несколько моделей просмотра для извлечения данных, фильтрации, добавления документов в Firestore и т. Д.
Само приложение почти на 100% состоит из SwiftUI, и я хотел бы сохранить его таким, просто вызов для моего собственного развития. Хотя я наткнулся на стену.
В приложении у меня есть серия представлений со списками NavigationView, в которые я передаю небольшие фрагменты данных во время навигации. Примером (это для учебных заведений) может быть Список школ> Список классов> Список учащихся в классе> Список оценок для учащихся. По сути, идеальное использование для просмотра навигации и множества списков.
Ошибка: когда я перехожу от одного списка к другому в стеке, я извлекаю данные из хранилища, которые загружаются на секунду (достаточно, чтобы список заполнялся), а затем "выгружаются" обратно в ничто. Вот код, в котором это происходит (я очистил его, чтобы сделать его максимально простым):
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("Классы не найдены"), и она действительно отображается. Итак, в основном, просмотр загрузок (это все в представлении Nav от родителя), он извлекает данные, которые отображаются на секунду (список заполняется), а затем выгружает эти данные по какой-то причине, оставляя мне только "Нет классов найденный".
Для большего контекста вот код для 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
}
}
}
И ДАЛЬНЕЙШИЙ родительский элемент этого представления (и фактически начального представления приложения):
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()
}
}
}
Знаю, что это много, но просто так у всех есть приказ родителей:
StartView > SchoolUserListView > ClassListView(здесь возникает ОШИБКА)
Кстати, SchoolUserListView использует метод fetchData точно так же, как ClassListView (где ошибка) и выводит его в список foreach, то же самое, но НЕТ проблем? Я просто не уверен, в чем проблема, и приветствую любую помощь!
Вот видео проблемы:https://imgur.com/a/kYtow6G
1 ответ
Починил это! Проблема заключалась в том, что объект EnvironmentObject для режима презентации передавался в представлении навигации. Кажется, это вызывает МНОГО нежелательного поведения. Будьте осторожны, передавая режим presentationMode, поскольку он вызывает перезагрузку данных (поскольку он обновляется).