Swift函数执行异常求助:先返回值再执行主体代码
问题分析
你的问题核心是Firestore的getDocuments是异步操作——它不会阻塞当前线程等待请求完成。当你调用getDocuments后,代码会立刻继续执行后续的print("[3]")和return coursesArray;只有当Firestore请求完成后,才会进入闭包执行元素追加操作,这就是为什么打印顺序异常、返回空数组的原因。
解决方案
下面提供两种主流解决方式,优先推荐现代Swift的async/await语法,代码更简洁易读。
方式1:使用Async/Await(Swift 5.5+)
将getUnapprovedCourses改为异步函数,用await等待Firestore请求完成:
func getUnapprovedCourses(account: String) async throws -> [Course] { print("===== [1] Main body of the function ===== \n") let db = Firestore.firestore() var coursesArray: [Course] = [] // 用await等待异步请求完成,替代闭包回调 let querySnapshot = try await db.collection("temp_courses") .whereField("teach_by", isEqualTo: account) .getDocuments() for document in querySnapshot.documents { let singleCourse: Course = try document.data(as: Course.self) print("===== [2] Append an element ===== \n") coursesArray.append(singleCourse) } print("===== [3] Return an array ===== \n") return coursesArray }
修改调用逻辑,用Task包裹异步操作(SwiftUI的onAppear本身是同步的):
.onAppear { Task { await getCoursesInfo() } } func getCoursesInfo() async { let userManager = UserManager() print("===== [0] Call the function ===== \n") do { coursesArray = try await userManager.getUnapprovedCourses(account: account) // 此处可执行数组填充完成后的UI更新逻辑 } catch { print("获取课程失败:\(error)") } }
方式2:使用闭包回调(兼容旧Swift版本)
如果项目暂不支持async/await,可以用闭包回调的方式,等异步操作完成后再处理结果:
func getUnapprovedCourses(account: String, completion: @escaping ([Course]?, Error?) -> Void) { print("===== [1] Main body of the function ===== \n") let db = Firestore.firestore() var coursesArray: [Course] = [] db.collection("temp_courses").whereField("teach_by", isEqualTo: account) .getDocuments() { (querySnapshot, err) in if let err = err { completion(nil, err) return } guard let documents = querySnapshot?.documents else { completion([], nil) return } for document in documents { do { let singleCourse: Course = try document.data(as: Course.self) print("===== [2] Append an element ===== \n") coursesArray.append(singleCourse) } catch { print("Place A error... [ FirestoreManager.swift -> UserManager -> getUnapprovedCourses ]") } } print("===== [3] Return an array ===== \n") completion(coursesArray, nil) } }
调用时传入闭包处理结果:
.onAppear { getCoursesInfo() } func getCoursesInfo() { let userManager = UserManager() print("===== [0] Call the function ===== \n") userManager.getUnapprovedCourses(account: account) { [weak self] courses, error in guard let self = self else { return } if let error = error { print("获取课程失败:\(error)") return } self.coursesArray = courses ?? [] // 此处更新UI } }
注意事项
- 无论哪种方式,都不要在主线程做阻塞操作,Firestore的异步设计就是为了避免UI卡顿。
- 使用
async/await时,必须将异步调用放在Task或async函数内部。
内容的提问来源于stack exchange,提问作者Milo Song
相关产品推荐
相关产品推荐

