swift - 第二次函数调用后才可用的值
问题描述
我有以下函数,它运行良好,但现在我需要函数中的值才能将其用于其他目的。但我的问题是我总是必须执行两次函数才能在函数的外部获得一个值(var valueOutOfFunction)。
var valueOutOfFunction = [(String)]()
func loadQuery(com:@escaping( [(Int, String)] -> ())){
var arrayOfTuples = [(Int, String)]()
db.collection("Data").whereField("age", isGreaterThanOrEqualTo: 1).whereField("age", isLessThanOrEqualTo: 50).whereField("gender", isEqualTo: "F").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for (index, document) in querySnapshot!.documents.enumerated() {
arrayOfTuples += [(index, document.documentID)]
}
}
com(arrayOfTuples)
}
}
然后我在这里调用它:
loadQuery { arr in
self.valueOutOfFunction = arr // Has a value in the first execution
}
print (valueOutOfFunction) //Executing the first time there is no value in the variable, the second time it have a value.
为什么它只是在第二次尝试可用,什么可以解决这个问题?谢谢!
解决方案
那是因为valueOutOfFunction
发生在那个被异步调用到 print 语句的闭包内部。此外,您正在执行else 语句之外的完成,该语句可能在您的 for 循环完成之前触发。您想要做的是从闭包本身控制流程,如下所示:
// move com(arrayOfTuples) up into the else block but outside of the for loop
func handleQuery() {
loadQuery { doStuffWithResult($0) }
// This line will run before the first line of doStuffWithResult
// It would be best to end the function logic at loadQuery
}
func doStuffWithResult(_ arrayOfTuples: [(Int, String)]) {
print(arrayOfTuples)
// Do other work here
}
您正在研究的是控制流。你想执行X if Y
已经发生了,Z if !Y
对吗?
我建议查看swift 的结果类型。这将帮助您使用闭包管理控制流。
一个例子:
typealias QueryResult = [(Int, String)]
enum QueryErrors: Error {
case couldNotFind
}
func loadQuery(_ result: @escaping (Result<QueryResult, Error>) -> Void) {
db.collection("Data").whereField("age", isGreaterThanOrEqualTo: 1).whereField("age", isLessThanOrEqualTo: 50).whereField("gender", isEqualTo: "F").getDocuments() { (querySnapshot, err) in
guard let documents = querySnapshot?.documents.enumerated() else {
// I think enumerated will give you an array of tuples... if not add this to the end of that line. After enumerated but before else
// enumerated().compactMap { ($0, $1) }
result(.failure(err ?? QueryErrors.couldNotFind))// passes back Firebase error if it exists or default error if it doesn't
return
}
result(.success(documents))
}
}
// how it works
loadQuery() { result in
switch(result) {
case .success(let arr): print(arr)
case .failure(let error): print(error)
}
}
推荐阅读
- mysql - 将重复的 MySQL 行压缩到链接 PK 和 FK 表中?
- node.js - 开玩笑更改了测试目录导致 beforeAll 未定义
- java - Java - 如何检查数组是否有值
- r - 如何根据列中的级别对重复值求和并输出计数表?
- python - 通过cmd运行脚本时没有名为“selenium/googletrans/tabula”的模块但在空闲时工作正常?
- node.js - 干净的接口,支持 Callbacks、Promises 和 async/await
- android - 在 React Native 上实现 Swipe 交互
- javascript - Paypal 错误 ppxo_no_token_passed_to_payment 又名“没有传递给付款的价值”
- mysql - MySQL中的日期函数
- android - 构建中的 Android :app:compileDebugJavaWithJavac 和 CompilationFailedException