Firestore数据已获取但返回数组为空的原因及解决方法
问题:Firestore数据获取函数返回空数组
我正在学习Swift,已经实现了从Firestore数据库获取数据的功能,通过Data Controller处理数据获取逻辑。调用接口能成功拿到数据(打印语句能看到),但自定义的fetchUnidades函数返回的[MyClassType]数组是空的。
函数代码如下:
func fetchUnidades(for foo: MyFirstEnum, and bar: MySecondEnum ) -> [MyClassType]{ let db = Firestore.firestore() let colPath = "my/firebase/path" let results = [MyClassType]() let collection = db.collection(colPath) collection.whereField("myField", isEqualTo: foo.rawValue).getDocuments() { querySnapshot, err in if let err = err { print("Error getting documents: \(err)") } else { for document in querySnapshot!.documents { do { print("\(document.documentID) => \(document.data())") // 1st print let newMyClass = try document.data(as: MyClassType.self) results.append(newMyClass) print("here") // 2nd print - debug breakpoint }catch (let error) { print("\(error)") } } } } print("DC - Recovered \(results.count) results") return results }
已知MyFirstEnum、MySecondEnum和MyClassType定义均正确,闭包内断点处打印results能看到已获取到数据,但函数执行到return语句时results为空,打印结果显示"DC - Recovered 0 results",返回的数组也为空。
问题原因
Firestore的getDocuments()是异步操作:它会在后台线程发起网络请求,不会阻塞当前主线程的执行流程。你的函数在调用getDocuments()后,立刻就执行了打印语句和return,这时候闭包还没开始执行(网络请求还没完成),所以results还是初始化时的空数组。等网络请求完成、闭包开始往results里添加数据时,函数早就已经返回空数组了。
解决方法
方法1:使用Completion Handler(兼容所有Swift版本)
修改函数,通过回调闭包返回结果,而不是直接返回数组:
func fetchUnidades(for foo: MyFirstEnum, and bar: MySecondEnum, completion: @escaping ([MyClassType]?, Error?) -> Void) { let db = Firestore.firestore() let colPath = "my/firebase/path" let collection = db.collection(colPath) collection.whereField("myField", isEqualTo: foo.rawValue).getDocuments() { querySnapshot, err in if let err = err { print("Error getting documents: \(err)") completion(nil, err) return } var results = [MyClassType]() for document in querySnapshot!.documents { do { print("\(document.documentID) => \(document.data())") let newMyClass = try document.data(as: MyClassType.self) results.append(newMyClass) print("here") } catch let error { print("\(error)") } } print("DC - Recovered \(results.count) results") completion(results, nil) } }
调用示例:
fetchUnidades(for: .yourEnumCase, and: .anotherEnumCase) { unidades, error in if let error = error { // 处理错误逻辑 return } // 在这里使用获取到的数据 if let unidades = unidades { print("成功获取\(unidades.count)条数据") } }
方法2:使用Async/Await(Swift 5.5+推荐)
如果你的项目使用Swift 5.5及以上版本,用异步等待语法可以让代码更简洁,逻辑更清晰:
func fetchUnidades(for foo: MyFirstEnum, and bar: MySecondEnum) async throws -> [MyClassType] { let db = Firestore.firestore() let colPath = "my/firebase/path" let collection = db.collection(colPath) // 异步等待请求完成 let querySnapshot = try await collection.whereField("myField", isEqualTo: foo.rawValue).getDocuments() var results = [MyClassType]() for document in querySnapshot.documents { let newMyClass = try document.data(as: MyClassType.self) results.append(newMyClass) print("\(document.documentID) => \(document.data())") } print("DC - Recovered \(results.count) results") return results }
调用示例(需要在异步上下文执行,比如Task中):
Task { do { let unidades = try await fetchUnidades(for: .yourEnumCase, and: .anotherEnumCase) // 使用获取到的数据 print("成功获取\(unidades.count)条数据") } catch { // 处理错误 print("获取数据失败:\(error)") } }
内容的提问来源于stack exchange,提问作者Lowb
相关产品推荐
相关产品推荐

