我从Firestore捕获数据并将其分配给数组,另一个问题的人告诉我也许我需要一个完成处理程序,但是我不知道如何工作,如果您能帮助我编写代码并进行解释,那将非常有帮助这个概念对我来说。
class PetsTVC: UITableViewController {
var db: Firestore!
let uid = Auth.auth().currentUser?.uid
var petslist = [String]()
var pid = ""
var pets = [paw]()
override func viewDidLoad() {
super.viewDidLoad()
self.loadPets()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func loadPets(){
let photo1 = UIImage(named: "Log")
db = Firestore.firestore()
db.collection("users").document(uid!).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else {
return
}
self.petslist = document["petslist"] as? Array ?? [""]
}
for pet in self.petslist {
self.db.collection("pets").document(pet).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else {
return
}
guard let data = document.data() else {
return
}
let pid = data["pid"] as! String? ?? ""
let petName = data["petName"] as! String? ?? ""
let infoPet = paw(id: pid, petName: petName, imagenMascota:photo1)
self.pets.insert(infoPet, at: 0)
}
}
}
}
如果您还需要代码中的其他内容,请告诉我,因为我在这里也很新,而且我不知道要问什么。
答案 0 :(得分:1)
完成处理程序是一些需要一些时间才能完成工作的函数的代码,您不需要继续等待就可以完成它。
例如,如果您的邮箱离我们很远,您就送孩子去取邮件。他们需要花一分钟时间才能转到邮箱,获取邮件,然后再回来,所以您将继续进行其他操作。由于孩子们很容易忘记,您将它们带回后,会在纸上写下一些说明如何处理。那张纸是完成处理程序。这张纸上的指示中最有可能的指示是将部分或全部邮件交给您,但也许包括首先过滤掉所有垃圾邮件或其他内容。
在您共享的代码中,您实际上有两个完成处理程序;在db.collection("users").document(uid!).getDocument
开始的行和self.db.collection("pets").document(pet).getDocument
开始的行中,{ }
内部的所有内容都是完成处理程序(或闭包)。
为了将结果输入到表中,您可能需要进行两项更改。第一个更改是将}
从self.petslist = document["petslist"] as? Array ?? [""]
行之后移到self.pets.insert(infoPet, at: 0)
行之后。
第二个更改是移动:
DispatchQueue.main.async {
self.tableView.reloadData()
}
从viewDidLoad()
到loadPets()
,并放在self.pets.insert(infoPet, at: 0)
行之后。这样,所有数据输入并处理后,表视图将重新加载。
现在,您要告诉孩子去拿邮件并将其放在篮子里,但是当孩子刚从前门出来时试图将邮件从篮子里拿出来,您需要等到孩子回来,然后从篮子里拿出邮件。
答案 1 :(得分:1)
您不需要完成处理程序,需要DispatchGroup
在上一次获取之后重新加载表视图。
并且您必须将循环放入第一次数据库访问的完成处理程序中
override func viewDidLoad() {
super.viewDidLoad()
self.loadPets()
}
func loadPets(){
let group = DispatchGroup()
let photo1 = UIImage(named: "Log")
db = Firestore.firestore()
db.collection("users").document(uid!).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else { return }
self.petslist = document["petslist"] as? [String] ?? []
if self.petslist.isEmpty {
DispatchQueue.main.async {
self.tableView.reloadData()
}
return
}
for pet in self.petslist {
group.enter()
self.db.collection("pets").document(pet).getDocument { documentSnapshot, error in
defer { group.leave() }
guard let document = documentSnapshot,
let data = document.data() else { return }
let pid = data["pid"] as? String ?? ""
let petName = data["petName"] as? String ?? ""
let infoPet = paw(id: pid, petName: petName, imagenMascota:photo1)
self.pets.insert(infoPet, at: 0)
}
}
group.notify(queue: .main) {
self.tableView.reloadData()
}
}
}
答案 2 :(得分:1)
让我们保持这种超级简单-可能不需要为此任务利用完成处理程序和调度组。
这是问题所在:Firestore是异步的,您只能在调用后的闭包内使用返回的数据。该循环之后的代码实际上将在循环中的代码之前执行,因为代码比Internet快。例如。
db.collection("users").document(uid!).getDocument... {
//data is valid here
print("Test")
}
print("Hello") //this code will execute and print Hello before Test is printed
因此,这是一个简单的解决方案,可加载用户数据,然后获取其宠物名称。我们有两个收藏夹
users
uid_0
name: "Leroy"
petslist:
0: "pet_0"
1: "pet_1"
2: "pet_2"
pets
pet_0
petName: "Spot"
pet_1
petName: "Rover"
pet_2
petName: "Fluffy"
和代码
func loadPets() {
let uid = "uid_1"
self.db.collection("users2").document(uid).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else {
return
}
let name = document["name"] as! String
print("Owner \(name) has the following pets:")
let petList = document["petslist"] as? Array ?? [""]
for pet in petList {
self.db.collection("pets").document(pet).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else {
return
}
let petName = document.get("petName") as? String ?? "No Pet Name"
print(petName) //Or reload the tableview**
}
}
}
}
和输出
Owner Leroy has the following pets:
Spot
Rover
Fluffy
话虽如此,您可以将闭包作为一种选择来做同样的事情,但我认为这超出了问题的范围。
**在此示例中,我保持简单。实际上,如果您有很多数据,则在加载每个宠物之后刷新tableView将导致闪烁,并且不是良好的UI体验。这是DispatchGroup可以发挥作用的地方,例如,您可以加载所有宠物,当最后一个宠物被加载时,离开调度组并然后更新tableView。
@Vadian在他的答案中概述了一个DispatchGroups版本,但这是使用DispatchGroup加载宠物名称的一种变体:
func loadPets() {
let uid = "uid_1"
self.db.collection("users2").document(uid).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else { return }
let name = document["name"] as! String
print("Owner \(name) has the following pets:")
let group = DispatchGroup()
let petList = document["petslist"] as? Array ?? [""]
for pet in petList {
group.enter()
self.db.collection("pets").document(pet).getDocument { documentSnapshot, error in
guard let document = documentSnapshot else { return }
let petName = document.get("petName") as? String ?? "No Pet Name"
print(petName)
group.leave()
}
}
group.notify(queue: .main) {
print("all pets loaded, reload tableview")
}
}
}