从 Firebase 检索数据以在 table 视图中显示数据时出现并发问题
Concurrency problem when retrieving data from Firebase to display it in a table view
我目前正在尝试从 Swift 中的实时数据库 (Firebase) 检索用户数据,并在 table 视图中显示用户名。
我有以下函数来从位于我的文件的主 class 中的数据库中检索所有用户(我附加到的变量用户已经作为空字符串数组在早些时候启动)。
func retrieveAllUsers(){
//hold all users
var userFullName = ""
self.usersReference.observeSingleEvent(of: .value, with: {(snapshot) in
// if marker ID has children it means this marker has already been created
//go in User ID uid
if snapshot.hasChildren() {
// go through all user ids
for child in snapshot.children {
//initialize a user name and first name
var userFirstName = ""
var userLastName = ""
let subSnap = child as! DataSnapshot
//get child key with format UserID: uid
let key = subSnap.key
// go inside User ID to retrieve name and first name of every user
DispatchQueue.main.async {
self.usersReference.child(key).observeSingleEvent(of: .value, with: { (snapshot2) in
// go through user parammters to only retrieve his name and first name
for grandChild in snapshot2.children {
let nameGatherer = grandChild as! DataSnapshot
if nameGatherer.key == "First Name:"{
userFirstName = nameGatherer.value as! String
}
if nameGatherer.key == "Last Name:"{
userLastName = nameGatherer.value as! String
}
}//end of loop inside user parameters
//add his full name to the list of users which we will then filter later on
userFullName = userFirstName + userLastName
self.users.append(userFullName)
self.tableView.reloadData()
print("IN CLOSURE: \(self.users)")
})// end of observation of one user parameters
}//end of dispatch async
print("OUTSIDE CLOSURE1: \(self.users)")
}//end of looking inside the user ID node
print("OUTSIDE CLOSURE2: \(self.users)")
}//end of if there are users children
print("OUTSIDE CLOSURE3: \(self.users)")
})//end of observation of users reference
print("OUTSIDE CLOSURE4: \(self.users)")
}
在我的 viewDidLoad 中我有
retrieveAllUsers()
print("USERS:\(self.users)")
tableView.reloadData()
我已经尝试使用 Dispatchmain.async 的并发(这是我第一次在我的程序中进行并发)。然而它似乎不起作用,因为我的 viewDidLoad 中的打印首先出现并且用户为空因此它没有出现在我的 table 视图中并且打印 ** print("OUTSIDE CLOSURE1: (self.users)")** 最后出现使用包含正确用户信息的数组。
谁能帮我在 table 视图中显示正确的用户信息?我真的很感激。
非常感谢!
安东尼
您的问题是因为您对 self.tableView.reloadData()
的调用实际上是在包含您的数据的 Firebase 回调中。此回调不保证在主线程上,所有UI操作必须在主线程上发生,总是。您需要包装调用以直接在 DispatchQueue.main.async
中重新加载 table(不嵌套在另一个调用中)以确保在主线程上调用它。
您也不需要在DispatchQueue.main.async
中调用嵌套调用。看我的例子:
func retrieveAllUsers(){
//hold all users
var userFullName = ""
self.usersReference.observeSingleEvent(of: .value, with: {(snapshot) in
// if marker ID has children it means this marker has already been created
//go in User ID uid
if snapshot.hasChildren() {
// go through all user ids
for child in snapshot.children {
//initialize a user name and first name
var userFirstName = ""
var userLastName = ""
let subSnap = child as! DataSnapshot
//get child key with format UserID: uid
let key = subSnap.key
// go inside User ID to retrieve name and first name of every user
self.usersReference.child(key).observeSingleEvent(of: .value, with: { (snapshot2) in
// go through user parammters to only retrieve his name and first name
for grandChild in snapshot2.children {
let nameGatherer = grandChild as! DataSnapshot
if nameGatherer.key == "First Name:"{
userFirstName = nameGatherer.value as! String
}
if nameGatherer.key == "Last Name:"{
userLastName = nameGatherer.value as! String
}
}//end of loop inside user parameters
//add his full name to the list of users which we will then filter later on
userFullName = userFirstName + userLastName
self.users.append(userFullName)
DispatchQueue.main.async {
self.tableView.reloadData()
}
print("IN CLOSURE: \(self.users)")
})// end of observation of one user parameters
print("OUTSIDE CLOSURE1: \(self.users)")
}//end of looking inside the user ID node
print("OUTSIDE CLOSURE2: \(self.users)")
}//end of if there are users children
print("OUTSIDE CLOSURE3: \(self.users)")
})//end of observation of users reference
print("OUTSIDE CLOSURE4: \(self.users)")
}
我目前正在尝试从 Swift 中的实时数据库 (Firebase) 检索用户数据,并在 table 视图中显示用户名。 我有以下函数来从位于我的文件的主 class 中的数据库中检索所有用户(我附加到的变量用户已经作为空字符串数组在早些时候启动)。
func retrieveAllUsers(){
//hold all users
var userFullName = ""
self.usersReference.observeSingleEvent(of: .value, with: {(snapshot) in
// if marker ID has children it means this marker has already been created
//go in User ID uid
if snapshot.hasChildren() {
// go through all user ids
for child in snapshot.children {
//initialize a user name and first name
var userFirstName = ""
var userLastName = ""
let subSnap = child as! DataSnapshot
//get child key with format UserID: uid
let key = subSnap.key
// go inside User ID to retrieve name and first name of every user
DispatchQueue.main.async {
self.usersReference.child(key).observeSingleEvent(of: .value, with: { (snapshot2) in
// go through user parammters to only retrieve his name and first name
for grandChild in snapshot2.children {
let nameGatherer = grandChild as! DataSnapshot
if nameGatherer.key == "First Name:"{
userFirstName = nameGatherer.value as! String
}
if nameGatherer.key == "Last Name:"{
userLastName = nameGatherer.value as! String
}
}//end of loop inside user parameters
//add his full name to the list of users which we will then filter later on
userFullName = userFirstName + userLastName
self.users.append(userFullName)
self.tableView.reloadData()
print("IN CLOSURE: \(self.users)")
})// end of observation of one user parameters
}//end of dispatch async
print("OUTSIDE CLOSURE1: \(self.users)")
}//end of looking inside the user ID node
print("OUTSIDE CLOSURE2: \(self.users)")
}//end of if there are users children
print("OUTSIDE CLOSURE3: \(self.users)")
})//end of observation of users reference
print("OUTSIDE CLOSURE4: \(self.users)")
}
在我的 viewDidLoad 中我有
retrieveAllUsers()
print("USERS:\(self.users)")
tableView.reloadData()
我已经尝试使用 Dispatchmain.async 的并发(这是我第一次在我的程序中进行并发)。然而它似乎不起作用,因为我的 viewDidLoad 中的打印首先出现并且用户为空因此它没有出现在我的 table 视图中并且打印 ** print("OUTSIDE CLOSURE1: (self.users)")** 最后出现使用包含正确用户信息的数组。
谁能帮我在 table 视图中显示正确的用户信息?我真的很感激。 非常感谢! 安东尼
您的问题是因为您对 self.tableView.reloadData()
的调用实际上是在包含您的数据的 Firebase 回调中。此回调不保证在主线程上,所有UI操作必须在主线程上发生,总是。您需要包装调用以直接在 DispatchQueue.main.async
中重新加载 table(不嵌套在另一个调用中)以确保在主线程上调用它。
您也不需要在DispatchQueue.main.async
中调用嵌套调用。看我的例子:
func retrieveAllUsers(){
//hold all users
var userFullName = ""
self.usersReference.observeSingleEvent(of: .value, with: {(snapshot) in
// if marker ID has children it means this marker has already been created
//go in User ID uid
if snapshot.hasChildren() {
// go through all user ids
for child in snapshot.children {
//initialize a user name and first name
var userFirstName = ""
var userLastName = ""
let subSnap = child as! DataSnapshot
//get child key with format UserID: uid
let key = subSnap.key
// go inside User ID to retrieve name and first name of every user
self.usersReference.child(key).observeSingleEvent(of: .value, with: { (snapshot2) in
// go through user parammters to only retrieve his name and first name
for grandChild in snapshot2.children {
let nameGatherer = grandChild as! DataSnapshot
if nameGatherer.key == "First Name:"{
userFirstName = nameGatherer.value as! String
}
if nameGatherer.key == "Last Name:"{
userLastName = nameGatherer.value as! String
}
}//end of loop inside user parameters
//add his full name to the list of users which we will then filter later on
userFullName = userFirstName + userLastName
self.users.append(userFullName)
DispatchQueue.main.async {
self.tableView.reloadData()
}
print("IN CLOSURE: \(self.users)")
})// end of observation of one user parameters
print("OUTSIDE CLOSURE1: \(self.users)")
}//end of looking inside the user ID node
print("OUTSIDE CLOSURE2: \(self.users)")
}//end of if there are users children
print("OUTSIDE CLOSURE3: \(self.users)")
})//end of observation of users reference
print("OUTSIDE CLOSURE4: \(self.users)")
}