在下面的函数中,我正在执行初始地理位置搜索查询,并希望处理找到的所有键,将它们附加到数组并将整个数组发回。
问题是observeReady
代码块被过早地执行,因此发送一个空数组(即使在该范围内找到了密钥,也不会在第一次加载时显示)。
我知道observeSingleEvent
调用是asynchronous
并且可能导致这种行为,所以我的问题是,我如何管理这个并确保在handler
块中执行observeReady
调用之前处理密钥?
func fetchInitialNearbyVenues(deviceLocation: CLLocation, radius: Double, handler: @escaping ([Venue]) -> ()) {
self.venuesArray.removeAll()
var savedByUsers = [String : String]()
let query = self.GEOFIRE_VENUES_LOC.query(at: deviceLocation, withRadius: radius)
query.observe(.keyEntered) { (key: String!, venueLocation: CLLocation!) in
self.REF_VENUES.child(key).observeSingleEvent(of: .value, with: { (snapshot) in
//process snapshot create and append Venue object to array
//...
//...
self.venuesArray.append(venue) //append Venue to array
})//end observeSingleEvent
}//end geofire query observe
query.observeReady {
handler(self.venuesArray) //PROBLEM: This gets executed prematurely thus sending an empty array via handler
}
}//end func
您所看到的是预期的行为。在所有相应的observeReady
被召唤之后,observe(.keyEntered)
保证着火。您可以使用一些简单的日志语句来验证这一点
query.observe(.keyEntered) { (key: String!, venueLocation: CLLocation!) in
print(".keyEntered")
}
query.observeReady {
print(".observeReady")
}
当你运行它时,它将打印:
.keyEntered
.keyEntered
...
.observeReady
这与API应该如何工作一致。但是在.keyEntered
中,您正在从Firebase加载其他数据,这是异步发生的。在.observeReady
解雇之后,这些电话确实可能完成。
因此,您需要自己实现必要的同步。检测是否已加载所有其他数据的一种简单方法是保留仍需要加载数据的所有密钥的计数。所以你每次添加一个密钥时+1
,以及每次加载场地数据时-1
:
let venuesToLoadCount = 0
query.observe(.keyEntered) { (key: String!, venueLocation: CLLocation!) in
venuesToLoadCount = venuesToLoadCount + 1
self.REF_VENUES.child(key).observeSingleEvent(of: .value, with: { (snapshot) in
venuesToLoadCount = venuesToLoadCount - 1
if venuesToLoadCount == 0 {
print("All done")
}
}
}
query.observeReady {
if venuesToLoadCount == 0 {
print("All done")
}
}