Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift firestore文档删除和崩溃时出现逻辑错误,但删除时没有逻辑错误_Swift_Firebase_Uitableview_Google Cloud Firestore_Nsindexpath - Fatal编程技术网

Swift 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 =

因此,我的目标是在条件为false且没有错误的情况下删除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

}
因此,这将删除单元格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循环的下一次迭代(可能在闭包完成之前)

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

  • 在querySnapshot!.documents中的文档的
    之前添加一个变量,以跟踪您是否找到参加活动的学生,如果您找到参加活动的学生(代替当前无效的返回语句),则在闭包中将此变量更新为
    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。很高兴我能帮上忙!