func yourFunctionName(finished: @escaping () -> Void) {
db.collection("countries")
.whereField("capital", isEqualTo: "washington")
.getDocuments { (snapshot, error) in
if error == nil{
for document in snapshot!.documents {
let documentData = document.data()
//print(document.documentID)
//print(documentData)
self.countries.append(document.documentID)
}
}
}
db.collection("countries")
.whereField("climate", isEqualTo: "pleasant")
.getDocuments { (snapshot, error) in
if error == nil {
for document in snapshot!.documents{
let documentData = document.data()
//print(document.documentID)
//print(documentData)
self.countries2.append(document.documentID)
}
}
}
finished()
}
viewDidLoad(){
yourFunctionName {
print(self.countries)
print(self.countries2)
}
}
我在输出中获得了空数组,尽管我应该使用@escaping调用im来打印数组。请有人在这里帮助我
答案 0 :(得分:0)
由于Firebase的函数实际上是异步的(它们可以在函数“ yourFunctionName”完成工作之后运行),因此它们返回空数组。 为了使其按预期工作(打印填充的数组) 您需要做的就是在Firebase的闭包内部调用它,就像这样:
func yourFunctionName(finished: @escaping () -> Void) {
db.collection("countries")
.whereField("capital", isEqualTo: "washington")
.getDocuments { (snapshot, error) in
if error == nil{
for document in snapshot!.documents {
let documentData = document.data()
self.countries.append(document.documentID)
finished() //<<< here
}
}
}
db.collection("countries")
.whereField("climate", isEqualTo: "pleasant")
.getDocuments { (snapshot, error) in
if error == nil {
for document in snapshot!.documents{
let documentData = document.data()
self.countries2.append(document.documentID)
finished() //<<< and here
}
}
}
}
答案 1 :(得分:0)
自从遇到此问题以来已有一段时间,但我相信问题在于您正在调用完成处理程序。我的意思是,您浏览文档后可以尝试直接调用它。一种想法可能是在完成时返回它,或者只是按照您的方式做。尝试以下方法:
func yourFunctionName(finished: @escaping ([YourDataType]?) -> Void) {
var countires: [Your Data Type] = []
db.collection("countries")
.whereField("capital", isEqualTo: "washington")
.getDocuments { (snapshot, error) in
if error == nil{
for document in snapshot!.documents {
let documentData = document.data()
//print(document.documentID)
//print(documentData)
countries.append(document.documentID)
}
finished(countries)
return
}
}
}
func yourSecondName(finished: @escaping([YouDataType]?) -> Void) {
var countries: [Your data type] = []
db.collection("countries")
.whereField("climate", isEqualTo: "pleasant")
.getDocuments { (snapshot, error) in
if error == nil {
for document in snapshot!.documents{
let documentData = document.data()
//print(document.documentID)
//print(documentData)
countires.append(document.documentID)
}
finished(countires)
return
}
}
func load() {
yourFunctionName() { countries in
print(countires)
}
yourSecondName() { countries in
print(countries)
}
}
viewDidLoad(){
load()
}
这将做的是,当您调用类型为@escaping的完成块并在其之后返回时,您将不再响应该完全块,因此将仅使用接收到的数据,因此不在乎关于该功能了。
根据我的一个好习惯,是将对象返回到完成块中,并使用单独的函数以使其更易于调试和更有效,并且还允许您使用@escaping返回,然后再返回。
您可以使用一个单独的方法来结合这两种方法并更新UI。如果要更新UI,请记住使用以下方法获取主队列:
DispathQueue.main.async {
// Update the UI here
}
应该可以。伟大的问题,希望对您有所帮助!
答案 2 :(得分:0)
您实际上并未逃脱闭包。 对于我所知道的,“ @ escaping”是一个标签,该函数的开发人员使用该标签来表示使用该函数的人,他/她正在传递的闭包将被存储,并稍后(在函数结束后)调用以进行异步和存储管理。在您的情况下,您可以调用函数本身立即传递的闭包。因此,关闭并没有逃脱。
firebase数据库也是异步的。意味着您不会立即收到结果
这部分:
{ (snapshot, error) in
if error == nil{
for document in snapshot!.documents {
let documentData = document.data()
//print(document.documentID)
//print(documentData)
self.countries.append(document.documentID)
}
}
}
本身是一个闭包,将在生成查询结果时稍后执行。如您在文档中所见,该函数正在转义闭包:https://firebase.google.com/docs/reference/swift/firebasefirestore/api/reference/Classes/Query.html#getdocumentssource:completion:
func getDocuments(source: FirestoreSource, completion: @escaping FIRQuerySnapshotBlock)
所以总结一下: Firebase查询的代码将在以后调用(但您不知道何时),并且在定义了Firebase回调之后(即被调用之前)立即调用闭包“ finished”。
您应该在firebase回调中调用完成的闭包,以在填充数组时使用它。
答案 3 :(得分:0)
我认为您的主要问题不是要填充您的arrays
,而是要使它变得更好。
我举了一个例子,说明如何更好地做到这一点。
首先,将大function
分成两部分,然后将其填充到function
中。
看下面的代码,观察viewDidLoad
的实现。
func countries(withCapital capital: String, completionHandler: (Result<Int, Error>) -> Void) {
db.collection("countries")
.whereField("capital", isEqualTo: capital)
.getDocuments { (snapshot, error) in
guard error == nil else {
completionHandler(.failure(error!))
return
}
let documents = snapshot!.documents
let ids = documents.map { $0.documentID }
completionHandler(.success(ids))
}
}
func countries(withClimate climate: String, completionHandler: (Result<Int, Error>) -> Void) {
db.collection("countries")
.whereField("climate", isEqualTo: climate)
.getDocuments { (snapshot, error) in
guard error == nil else {
completionHandler(.failure(error!))
return
}
let documents = snapshot!.documents
let ids = documents.map { $0.documentID }
completionHandler(.success(ids))
}
}
func viewDidLoad(){
countries(withClimate: "pleasant") { (result) in
switch result {
case .success(let countries):
print(countries)
self.countries2 = countries
default:
break
}
}
countries(withCapital: "washington") { (result) in
switch result {
case .success(let countries):
print(countries)
self.countries = countries
default:
break
}
}
}
如果必须使用它调用主线程调用
DispathQueue.main.async {
// code here
}
我希望它能对您有所帮助。