You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 17:45:20