Swift firestore文档删除和崩溃时出现逻辑错误,但删除时没有逻辑错误
因此,我的目标是在条件为false且没有错误的情况下删除firestore文档。起初,我有这个删除firestore文档的功能:Swift firestore文档删除和崩溃时出现逻辑错误,但删除时没有逻辑错误,swift,firebase,uitableview,google-cloud-firestore,nsindexpath,Swift,Firebase,Uitableview,Google Cloud Firestore,Nsindexpath,因此,我的目标是在条件为false且没有错误的情况下删除firestore文档。起初,我有这个删除firestore文档的功能: override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let deleteAction =
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (deleted, view, completion) in
let alert = UIAlertController(title: "Delete Event", message: "Are you sure you want to delete this event?", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (cancel) in
self.dismiss(animated: true, completion: nil)
}
let deleteEvent = UIAlertAction(title: "Delete", style: .destructive) { (deletion) in
guard let user = Auth.auth().currentUser else { return }
let documentid = self.documentsID[indexPath.row].docID
// let eventName = self.events[indexPath.row].eventName
let deleteIndex = client.index(withName: IndexName(rawValue: user.uid))
deleteIndex.deleteObject(withID: ObjectID(rawValue: self.algoliaObjectID[indexPath.row].algoliaObjectID)) { (result) in
if case .success(let response) = result {
print("Algolia document successfully deleted: \(response.wrapped)")
}
}
self.db.document("school_users/\(user.uid)/events/\(documentid)").delete { (error) in
guard error == nil else {
print("There was an error deleting the document.")
return
}
print("Deleted")
}
self.events.remove(at: indexPath.row)
tableView.reloadData()
}
alert.addAction(cancelAction)
alert.addAction(deleteEvent)
self.present(alert, animated: true, completion: nil)
}
deleteAction.backgroundColor = UIColor.systemRed
let config = UISwipeActionsConfiguration(actions: [deleteAction])
config.performsFirstActionWithFullSwipe = false
return config
}
因此,这将删除单元格fine和CloudFireStore中的文档。现在我在我的应用程序中遇到了一个问题,如果学校用户想要删除他们创建的活动,但一些学生用户已经购买了该活动,则该活动将删除“是”,但如果购买该活动的学生用户尝试查看他们购买的活动,值将为nil
,应用程序将崩溃,因为他们购买的事件的细节完全依赖于创建的事件(这不是一个概念,我不会改变,这只是应用程序的工作方式)
编辑代码为了解决这个问题,我决定在删除过程中添加一些逻辑:
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (deleted, view, completion) in
let alert = UIAlertController(title: "Delete Event", message: "Are you sure you want to delete this event?", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (cancel) in
self.dismiss(animated: true, completion: nil)
}
let deleteEvent = UIAlertAction(title: "Delete", style: .destructive) { (deletion) in
guard let user = Auth.auth().currentUser else { return }
let documentid = self.documentsID[indexPath.row].docID
let eventName = self.events[indexPath.row].eventName
let deleteIndex = client.index(withName: IndexName(rawValue: user.uid))
self.getTheSchoolsID { (id) in
guard let id = id else { return }
self.db.collection("student_users").whereField("school_id", isEqualTo: id).getDocuments { (querySnapshot, error) in
guard error == nil else {
print("Couldn't fetch the student users.")
return
}
for document in querySnapshot!.documents {
let userUUID = document.documentID
self.db.collection("student_users/\(userUUID)/events_bought").whereField("event_name", isEqualTo: eventName).getDocuments { (querySnapshotTwo, error) in
guard error == nil else {
print("Couldn't fetch if users are purchasing this event")
return
}
guard querySnapshotTwo?.isEmpty == true else {
self.showAlert(title: "Students Have Purchased This Event", message: "This event cannot be deleted until all students who have purchased this event have completely refunded their purchase of this event. Please be sure to make an announcement that this event will be deleted.")
return
}
}
}
deleteIndex.deleteObject(withID: ObjectID(rawValue: self.algoliaObjectID[indexPath.row].algoliaObjectID)) { (result) in
if case .success(let response) = result {
print("Algolia document successfully deleted: \(response.wrapped)")
}
}
self.db.document("school_users/\(user.uid)/events/\(documentid)").delete { (error) in
guard error == nil else {
print("There was an error deleting the document.")
return
}
print("Deleted")
}
self.events.remove(at: indexPath.row)
tableView.reloadData()
}
}
}
alert.addAction(cancelAction)
alert.addAction(deleteEvent)
self.present(alert, animated: true, completion: nil)
}
deleteAction.backgroundColor = UIColor.systemRed
let config = UISwipeActionsConfiguration(actions: [deleteAction])
config.performsFirstActionWithFullSwipe = false
return config
}
更新所以我完全退出了循环,如果查询为空,则继续执行删除过程。现在,我以学生用户的身份购买了一个事件,然后尝试以学校用户的身份删除同一事件,以此来测试这一点。出于某种原因,当我在第一个警报中按delete操作时,事件首先被删除,然后验证警报随即出现,但没有出现错误。是的,崩溃消失了,这很好,但是我查询中的return
方法实际上并没有返回并中断删除方法,它删除并显示错误,我没有得到
有什么建议吗?好的,我想我找到了问题所在。当您查看每个代表进入特定学校的用户的文档时,您会检查这些用户中的每一个是否正在参加试图删除的活动。问题是,每次执行此检查以查看用户是否正在参加活动时,您都会执行以下操作之一(基于
querysnapshotwo?.isEmpty
是否适用于该用户):
self.events.remove(在:indexPath.row)
处由于nil
值而崩溃。但我首先要确保,如果您发现有用户正在参加活动,然后显示警报,您将完全退出所有用户文档。然后,只有在浏览完所有用户文档后,发现没有人参加活动时,才执行删除操作
对最新情况的回应
太棒了,你所做的绝对是一个进步。当您发现有用户参与事件时(即guard querysnapshotwo?.isEmpty==true
计算结果为false
),它没有从delete方法返回的原因是,您只在闭包内返回。从本质上讲,您只需返回一行以外的内容:self.db.collection(“student\u users/\(userUUID)/events\u Build”).whereField(“event\u name”,isEqualTo:eventName)。getDocuments{(querySnapshotTwo,error)
然后您将在querySnapshot!.documents
中继续下一个文档
因此,即使学校的每个学生都参加了活动,您也将始终完成for循环并继续删除活动
它不起作用的另一个重要原因是,传递到getDocuments()调用中的闭包是异步运行的。这意味着每次调用时,它都会安排在将来某个随机时间运行闭包,然后立即从getDocuments()返回调用并执行for循环的下一次迭代(可能在闭包完成之前)
要解决此问题,我相信您只需要进行两项更改:
之前添加一个变量,以跟踪您是否找到参加活动的学生,如果您找到参加活动的学生(代替当前无效的返回语句),则在闭包中将此变量更新为true
- 在for循环之前创建调度组(write
)let group=DispatchGroup()
- 在for循环内的第一行调用
group.enter()
- 在for循环中getDocuments()闭包的最后一行调用
group.leave()
- 在for循环之后调用以下命令:
group.notify(队列:.main){
//删除代码在这里
}
好的,所以我基本上尝试了你的建议,但我不确定我是否完全按照你说的做对了,我将编辑我的帖子并显示片段。我也尝试了,但仍然没有效果。你回答中的两点也很有意义。我有一种感觉,那就是零值错误的问题。@wristbandstanks for upd告诉我你所做的一切!我已经更新了我的答案作为回应。嘿,你是一个传奇人物,我所需要的只是DispatchGroup()
实现,现在它工作得很好。非常感谢你的帮助!@wristbandsYou're welcome@dante。很高兴我能帮上忙!