Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 为什么我不能修改在闭包外部声明的变量?_Swift_Firebase_Google Cloud Firestore_Closures_Swift4 - Fatal编程技术网

Swift 为什么我不能修改在闭包外部声明的变量?

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(

每次测试代码时,都会向pickerUI返回一个空字符串,而不是学院名称。为什么呢?调试时,docData设置正确,但在关闭后变回空字符串

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。但我更喜欢两种回调,比如RTDBs
onDataChanged
onCancelled
(在Android中,但所有平台的逻辑都类似)。同意保护另一个演员,所以我在回答中更新了它。很明显,我通晓多种语言,这意味着我在每种语言中都同样不惯用-D