Swift 为什么我不能修改在闭包外部声明的变量?
每次测试代码时,都会向pickerUI返回一个空字符串,而不是学院名称。为什么呢?调试时,docData设置正确,但在关闭后变回空字符串Swift 为什么我不能修改在闭包外部声明的变量?,swift,firebase,google-cloud-firestore,closures,swift4,Swift,Firebase,Google Cloud Firestore,Closures,Swift4,每次测试代码时,都会向pickerUI返回一个空字符串,而不是学院名称。为什么呢?调试时,docData设置正确,但在关闭后变回空字符串 var ans = ""; var pickerData = [Any?](); let db = Firestore.firestore(); override func viewDidLoad() { super.viewDidLoad(); let docRef = db.collection("colleges").document(
var ans = "";
var pickerData = [Any?]();
let db = Firestore.firestore();
override func viewDidLoad() {
super.viewDidLoad();
let docRef = db.collection("colleges").document("UMD");
var docData = "";
docRef.getDocument { ( document, error) in
if error == nil {
docData = document!.get("Name") as! String;
} else{
}
}
pickerData.append(docData);
picker.delegate = self
picker.dataSource = self
}
这是因为数据是从Firestore异步加载的,在加载过程中,主代码会继续运行。通过放置几个日志语句最容易看到:
let docRef = db.collection("colleges").document("UMD")
print("Before starting to get data")
docRef.getDocument { ( document, error) in
print("Got data")
}
print("After starting to get data")
运行此代码时,它会打印:
在开始获取数据之前
在开始获取数据之后
得到数据
这可能不是您期望的顺序,但它确实完全解释了代码无法工作的原因。运行pickerData.append(docData)
时,docData=document!。获取(“名称”)为!字符串
尚未运行
因此,任何需要数据库数据的代码都需要在闭包内,或者从闭包中调用:
let docRef = db.collection("colleges").document("UMD")
var docData = ""
docRef.getDocument { ( document, error) in
if error == nil {
docData = document!.get("Name") as? String ?? "No Name"
pickerData.append(docData)
picker.delegate = self
picker.dataSource = self
} else{
}
}
另见:
- ,它还显示使用自定义闭包将自己的代码保留在
闭包之外getDocument
- ,显示使用调度组保留代码
getDocument
是异步工作的。代码不一定按行的顺序运行。和–无关–Any?
是Swift中最差的类型。Downvoter:你能解释一下你为什么被否决吗?回答得很好!不知道为什么会被否决。你不需要这个;每行之后。另外,安全地展开选项可能是一个好主意guard let doc=document else{return}
然后let docData=doc.get(“Name”)as?一串“没有名字”
嘿,杰。分号的意思很好,我把它们去掉了。我将离开硬演员阵容,因为闭包保证会得到一个错误或一个文档。如果不满足保证,硬铸只能失败,这。。。嗯。。。这不是保证的意义。:)同意!我想知道为什么显示FIRDocumentSnapshotBlock的两个参数都是可选的-我猜如果有错误,那么快照可能是零?随便。。虽然这部分.get(“Name”)
需要它,就像文档没有名称字段一样,它会崩溃。哦,我不太喜欢这个API签名。对于这种类型的异步数据,flatter只有一个包装器对象,因此该对象永远不会为null。但我更喜欢两种回调,比如RTDBsonDataChanged
和onCancelled
(在Android中,但所有平台的逻辑都类似)。同意保护另一个演员,所以我在回答中更新了它。很明显,我通晓多种语言,这意味着我在每种语言中都同样不惯用-D