firestore文档在逻辑错误的情况下删除并崩溃,但在没有逻辑的情况下可以删除



因此,我的目标是在条件为false且没有错误的情况下删除firestore文档。起初,我有一个删除消防仓库文件的功能:

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
}

所以这也删除了云存储中的单元格和文档。现在我在我的应用程序中遇到了一个问题,如果学校用户想删除他们创建的活动,但一些学生用户已经购买了该活动,该活动将删除是的,但如果购买该活动的学生用户试图查看他们购买的活动,值将为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

}

UPDATE所以我完全退出了循环,然后如果查询为空,我将继续执行删除过程。现在,我以学生用户的身份购买了一个活动,然后尝试以学校用户的身份删除同一个活动。出于某种原因,当我在第一个警报中按下删除操作时,事件首先被删除,然后验证警报立即出现,但崩溃时没有任何错误。是的,崩溃消失了,这很好,但我的查询中的return方法实际上并没有返回并突破删除方法,它删除并显示错误,我没有得到。

有什么建议吗?

好的,我想我发现了问题。当您浏览代表去特定学校的用户的每个文档时,您会检查这些用户中的每一个是否正在参加试图删除的活动。问题是,每次检查用户是否参加活动时,都要执行以下操作之一(根据该用户的querySnapshotTwo?.isEmpty是否为真(:

  1. 如果用户正在参加活动,则会显示一条警告,说明无法删除该活动(因此,这种情况会发生多次,而不仅仅是一次(,或:
  2. 如果用户没有参加活动,它会执行删除事件操作(因此,如果多个用户没有参加活动,这种情况也会发生多次(

我不确定是什么原因导致应用程序在self.events.remove(at: indexPath.row)nil值而崩溃。但是,如果发现用户正在参加活动并显示警报,我首先要确保完全退出循环浏览所有用户文档。然后,只有在浏览所有用户文档后,发现没有人参加活动时,才执行删除操作。

对更新的响应

太棒了,你所做的绝对是一个进步。当您发现用户参与事件时(即,当guard querySnapshotTwo?.isEmpty == true评估为false时(,它不会从delete方法返回的原因是因为您只在闭包内返回。从本质上讲,您只是在返回:self.db.collection("student_users/(userUUID)/events_bought").whereField("event_name", isEqualTo: eventName).getDocuments { (querySnapshotTwo, error)然后,您将继续使用querySnapshot!.documents中的下一个文档。

因此,即使学校的每个学生都参加了活动,你也会完成for循环,并继续删除活动!

它不起作用的另一个重要原因是,传递给getDocument((调用的闭包是异步运行的。这意味着,每次调用时,它都会将闭包安排在未来的某个随机时间运行,然后立即从getDocuments((调用返回并执行for循环的下一次迭代(可能在闭包完成之前(。

要解决这个问题,我相信你只需要做2个更改:

  1. for document in querySnapshot!.documents之前添加一个变量,以跟踪您是否找到了正在参加活动的学生,如果您发现有学生正在参加活动,则在闭包内将此变量更新为true(代替当前无效的返回语句(
  2. 您需要使用DispatchGroup,以便在异步检查每个学生后才执行删除操作。以下是关于如何使用调度组的简短教程。在您的情况下:
    • 在for循环之前创建调度组(写入let group = DispatchGroup()(
    • 在for循环内的第一行调用group.enter()
    • 在for循环内getDocuments((闭包的最后一行调用group.leave()
    • 在for循环之后立即调用以下命令:
group.notify(queue: .main) {
// deletion code goes here
}

相关内容

最新更新