我在编写代码时遇到过几次这个问题,我想我只是不理解SwiftUI执行代码顺序的方式。
我在上下文模型中有一个方法,它从Firebase中获取数据,我在.onAppear
中调用了这个方法,但是在运行了整个for循环之后,这个方法并没有执行方法中的最后一行。
当我在不同的位置设置断点时,代码似乎首先只是运行,而没有进行for循环,然后它再次返回到方法,然后运行一次for循环,然后它跳到其他一些奇怪的位置,然后再次返回到方法...
我想我就是不明白?
与主/后台线程有关吗?您能帮助我吗?
这是我的代码。
调用方法getTeachersAndCoursesInSchool
的UI视图的一部分
VStack {
//Title
Text("Settings")
.font(.title)
Spacer()
NavigationView {
VStack {
NavigationLink {
ManageCourses()
.onAppear {
model.getTeachersAndCoursesInSchool()
}
} label: {
ZStack {
// ...
}
}
}
}
}
下面是我的方法的for循环:
//Get a reference to the teacher list of the school
let teachersInSchool = schoolColl.document("TeacherList")
//Get teacherlist document data
teachersInSchool.getDocument { docSnapshot, docError in
if docError == nil && docSnapshot != nil {
//Create temporary modelArr to append teachermodel to
var tempTeacherAndCoursesInSchoolArr = [TeacherModel]()
//Loop through all FB teachers collections in local array and get their teacherData
for name in teachersInSchoolArr {
//Get reference to each teachers data document and get the document data
schoolColl.document("Teachers").collection(name).document("Teacher data").getDocument {
teacherDataSnapshot, teacherDataError in
//check for error in getting snapshot
if teacherDataError == nil {
//Load teacher data from FB
//check for snapshot is not nil
if let teacherDataSnapshot = teacherDataSnapshot {
do {
//Set local variable to teacher data
let teacherData: TeacherModel = try teacherDataSnapshot.data(as: TeacherModel.self)
//Append teacher to total contentmodel array of teacherdata
tempTeacherAndCoursesInSchoolArr.append(teacherData)
} catch {
//Handle error
}
}
} else {
//TODO: Error in loading data, handle error
}
}
}
//Assign all teacher and their courses to contentmodel data
self.teacherAndCoursesInSchool = tempTeacherAndCoursesInSchoolArr
} else {
//TODO: handle error in fetching teacher Data
}
}
这个方法正确地将数据赋给了tempTeacherAndCoursesInSchoolArr
,但是在最后一行,这个方法没有将tempTeacherAndCoursesInSchoolArr
赋给self.teacherAndCoursesInSchool
,为什么它不这样做呢?
1条答案
按热度按时间1sbrub3j1#
Firebase的大多数API调用都是异步的:当您请求Firestore为您获取文档时,它需要与后端进行通信,即使是在快速连接上,这也需要一些时间。
要处理此问题,可以使用两种方法:callbacks和
async
/await
。这两种方法都能很好地工作,但是您可能会发现async/await更容易阅读。如果您对详细信息感兴趣,请查看我的blog post Calling asynchronous Firebase APIs from Swift - Callbacks, Combine, and async/await | Peter Friese。在代码片段中,使用完成处理程序来处理异步调用返回后
getDocuments
返回的文档:但是,将
tempTeacherAndCoursesInSchoolArr
赋值给self.teacherAndCoursesInSchool
的代码位于完成处理程序的 * 外部 *,因此它将在调用完成处理程序 * 之前 * 被调用。您可以通过以下几种方法解决此问题:
1.使用Swift的async/await获取数据,然后使用
Task
组(请参阅Paul的excellent article,了解它们的工作原理)并行获取所有教师的数据,并在接收到所有数据后聚合它们。1.您可能还想考虑使用collection group query-看起来您的数据结构应该可以实现这一点。
通常,迭代集合的元素并对每个元素执行Firestore查询被认为是一种不好的做法,因为这会降低应用的性能,因为它将执行N+1个网络请求,而它可以只发送一个网络请求(使用集合组查询)。