firebase 我不了解呼叫onAppear时程式码的执行顺序

r3i60tvu  于 2022-12-14  发布在  其他
关注(0)|答案(1)|浏览(106)

我在编写代码时遇到过几次这个问题,我想我只是不理解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,为什么它不这样做呢?

1sbrub3j

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返回的文档:

schoolColl.document("Teachers").collection(name).document("Teacher data").getDocument { teacherDataSnapshot, teacherDataError in
  // ...
}

但是,将tempTeacherAndCoursesInSchoolArr赋值给self.teacherAndCoursesInSchool的代码位于完成处理程序的 * 外部 *,因此它将在调用完成处理程序 * 之前 * 被调用。
您可以通过以下几种方法解决此问题:
1.使用Swift的async/await获取数据,然后使用Task组(请参阅Paul的excellent article,了解它们的工作原理)并行获取所有教师的数据,并在接收到所有数据后聚合它们。
1.您可能还想考虑使用collection group query-看起来您的数据结构应该可以实现这一点。
通常,迭代集合的元素并对每个元素执行Firestore查询被认为是一种不好的做法,因为这会降低应用的性能,因为它将执行N+1个网络请求,而它可以只发送一个网络请求(使用集合组查询)。

相关问题