【问题标题】:Unable to access variable inside closure swift无法快速访问闭包内的变量
【发布时间】:2019-12-23 14:06:15
【问题描述】:

我正在尝试将我的 firebase 数据库数据放入一个变量中以在我的项目中使用它

var someArray = [Array]()
let dbRef = Database.database().reference().child("SomeDatabase")


func loadSomeDatabaseData {
   dbRef.observeSingleEvent(of: .value) { (snapshot) in
       let someDict = snapshot.value as! [String:Any]
       let keysOfSomeDict = Array(someDict.keys)
       self.someArray.append(contentsOf: keysOfSomeDict)
       self.collectionView?.reloadData()
   }
}

我尝试在 viewDidload 中调用 loadSomeDatabaseData(),然后打印 someArray,结果是一个空数组。我知道 keysOfSomeDict 数组有我想要的正确数据,因为我尝试直接在闭包内打印这个数组。不过,我也希望能够在我的应用程序的其他地方打印和使用这些数据。

【问题讨论】:

    标签: swift firebase closures


    【解决方案1】:

    Firebase observeSingleEvent 方法是 asynchronous 方法。它只是在后台执行,因为从 Firebase 获取数据需要时间。

    如果你立即打印数组意味着你只会得到空数组。

    从 Firebase 获取数据后打印数组。为此,您可以使用escaping closure

    函数声明:

      func loadSomeDatabaseData(resultArray : @escaping([Array])->()) {
           dbRef.observeSingleEvent(of: .value) { (snapshot) in
               let someDict = snapshot.value as! [String:Any]
               let keysOfSomeDict = Array(someDict.keys)
               self.someArray.append(contentsOf: keysOfSomeDict)
               resultArray(self.someArray)
           }
        }
    

    函数调用:

    self.loadSomeDatabaseData{(firebaseReposne) in
       print("FirebaseData" , firebaseReposne)  // Hope here you will get your firebase data.
         self.collectionView?.reloadData()
    }
    

    【讨论】:

    • 这很好用!但是我有一个问题:为什么在转义后放置 [Array] ?这是指什么?它不会让我,但我把 [String] 改为,这有效。
    • 两者都可以工作,您将变量声明为 'var someArray = [Array]()' 就像这样知道。所以我以相同的格式传递数据。所以我把 [Array] 放在转义闭包中
    【解决方案2】:

    observeSingleEvent 是异步的。所以在调用loadSomeDatabaseData 之后立即打印someArray 将导致一个空数组。从 Firebase api 检索数据需要一些时间。

    要在应用程序的其他地方使用此数据,您可以设置一个标志来指示数据已加载或发送通知以通知数据可用。

    【讨论】:

    • 我对编程很陌生,你能用更简单的术语解释一下吗?我理解它是异步的并且需要等待的事实,但我不明白我是如何在我的项目中做到这一点的。我希望 collectionView.reloadData() 方法能解决这个问题,但它没有。
    • 我没有尝试使用来自 keysOfSomeDict 的数据填充集合视图,因为我认为它不起作用,因为它打印为空数组。目前,我正在使用包含项目名称和图像的 plist 填充我的 collectionview。我想用 firebase 实现同样的效果 - 我的数据库中项目的字符串应该显示在每个 collectionview 单元格的标签中。
    • 如果在从 Firebase 加载数据后执行闭包并且 self.someArray.append(contentsOf: keysOfSomeDict) 将结果附加到 someArray。您应该能够使用 someArray 作为集合视图的数据源。因此,不要使用 plist,而是使用 someArray。最初,collection view 不会显示任何数据,但是当执行闭包时,collection view 将重新加载数组中的数据。
    • 成功了,谢谢你的解释!让我感到困惑的是我假设因为它会打印一个空数组,无论如何该数组都是空的,但是在collectionview中使用它时数组似乎不是空的,因为我正在调用允许的collectionview.reloaddata方法如果我理解正确,则执行给数组值的闭包。但是,如果我不使用闭包中的数据来填充我可以重新加载的集合视图,但我想将该变量用于其他用途怎么办?我该怎么做?
    • 很高兴听到它有效。澄清一下:闭包是异步执行的,所以不是立即执行的。仅在从 firebase 加载数据之后。从那一刻起,数据被加载并且您可以使用它,就像上面的例子一样,通过填充一个数组并重新加载视图。在没有集合视图的情况下使用数据,在视图或视图控制器上实现一个函数来处理/显示数组中的数据。然后可以调用此函数而不是集合视图重新加载函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    • 2015-01-05
    • 1970-01-01
    相关资源
    最近更新 更多