簡體   English   中英

我不明白調用 onAppear 時代碼執行的順序

[英]I don't understand the order that code executes when calling onAppear

我在編碼時遇到過幾次這個問題,我想我只是不明白 SwiftUI 執行代碼順序的方式。

我的上下文 model 中有一個方法,它從我在 .onAppear 中調用的.onAppear獲取數據。 但是該方法在運行整個 for 循環后不會執行方法中的最后一行。

當我在不同的地方設置斷點時,似乎代碼首先只是在沒有進行 for 循環的情況下運行,然后它再次返回到該方法,然后運行一次 for 循環,然后跳轉到其他一些奇怪的地方,然后然后再次回到方法......

我想我只是不明白?

它與主/后台線程有關嗎? 你能幫助我嗎?

這是我的代碼。

我的 UI 視圖的一部分調用方法getTeachersAndCoursesInSchool

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 它為什么不那樣做?

Firebase 的大部分 API 調用都是異步的:當您要求 Firestore 為您獲取文檔時,它需要與后端通信,而且 - 即使是在快速連接上 - 這也需要一些時間。

要解決這個問題,您可以使用兩種方法:回調和async / await 兩者都可以正常工作,但您可能會發現 async/await 更易於閱讀。 如果您對詳細信息感興趣,請查看我的博客文章從 Swift 調用異步 Firebase API - 回調、組合和異步/等待 | 彼得弗里斯

在您的代碼片段中,您使用完成處理程序來處理異步調用返回后getDocuments返回的文檔:

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

但是,將tempTeacherAndCoursesInSchoolArr分配給self.teacherAndCoursesInSchool的代碼在完成處理程序之外,因此甚至會在調用完成處理程序之前調用它。

您可以通過幾種方式解決此問題:

  1. 使用 Swift 的 async/await 獲取數據,然后使用Task組(請參閱 Paul 關於其工作原理的優秀文章)並行獲取所有教師的數據,並在收到所有數據后聚合它們。

  2. 您可能還想考慮使用集合組查詢- 看起來您的數據的結構應該使這成為可能。

通常,遍歷集合的元素並對每個元素執行 Firestore 查詢被認為是一種不好的做法,因為它會降低應用程序的性能,因為它會執行 N+1.network 請求,而實際上它只能發送一個single.network 請求(使用集合組查詢)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM