我有代码需要在Firebase完成下载我负责下载的任务后立即执行。问题是此代码始终在下载完成之前运行。
if currentVersionNumber < newVersionNumber {
print("Feed: button donwloading cards")
//self.databaseButton.setTitle("Downloading New Cards...", for: .normal)
ref.observe(.value, with: { snapshot in
print("Feed: Checking for new cards from firebase")
for item in snapshot.children {
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
// Uh-oh, an error occurred!
print("Feed: error occured")
print(error)
} else {
// Data for "images/island.jpg" is returned
cards.imageName = data!
print("Feed: downloaded \(cards.name)")
}
}
// add to updated list of cards
updateCards.append(cards);
}
})
} else {
print("Feed: cards are up to date. \(currentVersionNumber)")
}
})
此代码从Firebase数据库下载我想要的项目,但在完成之前将在其后运行任何代码。如何制作它以便我可以选择在下载完成后立即执行代码块?
答案 0 :(得分:2)
这是因为 Firebase 的所有更新都发生在后台线程中,而您的代码在主线程上执行。要处理这个问题,请在一个函数中调用firebase方法,该函数具有一个在firebase下载完成后立即调用的闭包。
例如:
在viewDidLoad
:
override func viewDidLoad() {
super.viewDidLoad()
fetchData {
//do whatever action you wish to perform on download completion
mainTableView.reloadData()
}
}
func fetchData(andOnCompletion completion:@escaping ()->()){
ref.observe(.value, with: { snapshot in
print("Feed: Checking for new cards from firebase")
for item in snapshot.children {
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
// Uh-oh, an error occurred!
print("Feed: error occured")
print(error)
} else {
// Data for "images/island.jpg" is returned
cards.imageName = data!
print("Feed: downloaded \(cards.name)")
}
}
// add to updated list of cards
updateCards.append(cards);
}
//call the block when done processing
completion()
})
}
答案 1 :(得分:2)
这些网络请求运行异步,因此在网络请求完成后,它们之后的任何代码都将继续运行。
你应该在内部闭包中移动updateCards.append(cards),这样它就不会被调用,直到第二个闭包完成,然后如果你有其他代码需要在完成后运行,你可以移动它在此函数内部或使用带有完成处理程序的闭包,以确保在运行任何更多依赖于响应的代码之前完成所有网络请求。
getCardData { [weak self] in
// do whatever you need to do after completion
}
func getCardData(_ completion: () -> ()) {
print("Feed: button donwloading cards")
//self.databaseButton.setTitle("Downloading New Cards...", for: .normal)
ref.observe(.value, with: { snapshot in
print("Feed: Checking for new cards from firebase")
for item in snapshot.children {
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
// Uh-oh, an error occurred!
print("Feed: error occured")
print(error)
completion() // this is where you would normally throw an error or have a closure that accepts an optional error you would pass in to know it failed
} else {
// Data for "images/island.jpg" is returned
cards.imageName = data!
print("Feed: downloaded \(cards.name)")
updateCards.append(cards);
completion()// now you know all network requests are complete
}
}
}
})
}
答案 2 :(得分:1)
通过在下载中添加if语句来管理以解决我的问题,该语句检查附加到updateCards的卡的数量是否等于快照中的卡的数量。感谢回答这个问题的两个人,因为我也使用了completion()方法,很高兴我去了解这个我不知道存在的概念。