firestore 文档删除并因逻辑错误而崩溃,但在没有逻辑的情况下删除正常 对更新的响应

问题描述

所以我的目标是在条件为假且没有错误的情况下删除 firestore 文档。一开始我有这个删除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

}

所以这会很好地删除单元格和云 Firestore 中的文档。现在我在我的应用程序中遇到了一个问题,如果学校用户想要删除他们创建的活动,但一些学生用户已经购买了此活动,则此活动将删除是,但如果购买该活动的学生用户尝试查看他们购买的事件,值将为 nil 并且应用程序将崩溃,因为他们购买的事件的详细信息完全依赖于创建的事件(这不是我不会改变的概念,这只是应用程序的方式有效)。

编辑代码为了解决这个问题,我决定在删除过程中添加一些逻辑:

   override func tableView(_ tableView: UITableView,trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    
    
    let deleteAction = UIContextualAction(style: .destructive,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,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 循环并继续删除该活动!

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

要解决此问题,我相信您只需要进行 2 处更改:

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...