【问题标题】:array index out of bounds when deleting from firebase从firebase删除时数组索引超出范围
【发布时间】:2019-11-12 04:43:55
【问题描述】:

当我尝试从 firebase 中的子节点中删除节点时,它会使我的代码崩溃,并给出一个致命错误,即“索引超出范围”。最终结果是从 UID 中删除与 ID 关联的数据。我附上了删除单元格的代码

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if (editingStyle == .delete) {
        var listOfUID = [String]()
        let ref = Database.database().reference().child(currentEmail!)

        ref.observe(.childAdded , with: { snapshot in
            if !snapshot.exists() {return}

            print(snapshot.key)

            let listOfUID = [snapshot.key]
            let name = listOfUID[indexPath.row]

            ref.queryOrdered(byChild: name ).queryEqual(toValue: name).observe(.childAdded, with: { (snapshot) in
                snapshot.ref.removeValue(completionBlock: { (error, reference) in
                    if error != nil {
                        print("There has been an error:\(error)")

                    }
                  data.remove(at: indexPath.row)
                  tableView.deleteRows(at: [indexPath], with: .left)
                })
            })
        })


    }
 }

let name = listOfUID[indexPath.row - 1]之类的某些原因也无法修复它。

我还认为值得一提的是,当前的电子邮件有一个扫描仪可以取出“。”

我已经上传了数据库的结构是如何设置的

{
  "email@yahoocom" : {
    "-LtUztWPbQias7bh5C2L" : {
      "message" : "Didn’t",
      "teamName" : "jah"
    },
    "-LtUzumEkb2kjK4qeU6E" : {
      "message" : "D d",
      "teamName" : "did if"
    },
    "-LtVCbxDu6DqxWv7LHzp" : {
      "message" : "Cc’d",
      "teamName" : "xdfff"
    }
  },
  "nice@nicecom" : {
    "-LtSjXIKnKXKgp-XCzdP" : {
      "message" : "Test 2",
      "teamName" : "test 1"
    }
  }
}

【问题讨论】:

  • 如果您的问题与 XCode IDE 有关,请仅使用 xcode 标记。有关 iOS 编程的一般问题,请使用ios 标记。
  • 明白了,抱歉 :)
  • 该代码存在许多问题会导致它崩溃,更不用说将观察者添加到要删除的节点(?)。我建议重新考虑如何将数据存储在 tableView 数据源中的策略。如果您读取一组 Firebase 节点并将它们保存在一个数组中,那么您当时也将拥有节点键,因此也将它们存储在数据源中。从那里,当删除一行时,您将知道它是什么节点键,并可以直接删除该节点。这避免了必须查询节点然后删除找到的节点。
  • 我有点困惑,因为我一直在为整个项目使用 firebase api...不会撒谎我不敢相信创建删除功能会如此令人沮丧而且要花很多时间lul
  • 这令人沮丧,因为它是如何完成的。这实际上是一个简单的过程,但该代码过于复杂;您不需要 .childAdded 甚至查询来完成这项工作。一般来说,您不必使用已知键查询节点然后转身删除它。当节点加载到您的数据源开始时,您可以跟踪它们来自 snapshot.key 的节点。当您滑动删除时,读取从滑动中获取行索引,在 dataSource 数组中查找该对象,获取节点键。然后将其从 Firebase 中移除。

标签: ios swift firebase firebase-realtime-database


【解决方案1】:

有很多方法可以改进代码。我不得不在这里做出一堆假设,因为这个问题有些含糊。两个建议:

1) 不要使用电子邮件地址作为节点键。正如您提到的那样,您必须操纵它们,如果用户的电子邮件发生变化怎么办?您必须仔细阅读并写回它使用的每个地方。使用 .childByAutoId 创建一个密钥,然后将发件人 uid 存储为子项。 uid 始终指向该用户。使用 .childByAutoId 可将键与数据解除关联,从而提供更大的灵活性。

2) 你不需要查询一个节点来删除它。如果你知道密钥,你可以用它来删除

您的用户和团队节点应如下所示:

users
   uid_0 //a users uid
      user_name: "Henry"
      email: "henry@thing.com"
      team: "team_0"

   uid_1 //another users uid
      user_name: "Leroy"
      email: "leroy@jenkins.com"
      team: "team_1"

teams
   team_0 //created with .childByAutoId
      team_name: "Cool Team"
   team_1
      team_name: "Awesome Team"

如果团队 A 变为酷团队,您可以在一个地方更改它,而不是为每个用户更改。此外,您可以更改用户电子邮件,而不会影响应用中的任何其他代码或节点。

问题中的信息不多,但看起来其他用户发给用户的消息存储在 Universalscout 节点中

universalscout
   uid_0 //the uid of the user that's receiving the message
      message_id_0 //created with childByAutoId
         from_uid: "uid_1" //the uid of the user that sent the message
         msg: "Didn't"
      message_id_1
         from_uid: "uid_2"
         msg: "D d"
      message_id_2
         from_uid: "uid_3"
         msg: "Cc'd"

然后是一个类来保存消息数据并存储在支持 tableView 的 dataSource 中

class MessageClass {
   var msg_id = ""
   var from_uid = ""
   var msg = ""
)

然后是一个类 dataSource 数组来存储它们

var myMessageArray = [MessageClass]()

因此,在读取时,遍历 uid_0 中的消息,读取每条消息,创建一个 MessageClass 来存储 msg_id、消息来源和消息。将每个类添加到 dataSource 数组。看来您知道如何从 Firebase 读取数据并填充数据源,因此我将跳过该代码。

那么最后在删除的时候。

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if (editingStyle == .delete) {
        let messageToDelete = myMessageArray[indexPath.row]
        let firebaseKey = messageToDelete.msg_id
        let ref = your_firebase.child("universalscout").child(this users uid).child(firebaseKey)
        ref.remove()
        //remove the row from the dataSource
        //reload the tableView
    }
 }

问题中没有提到的一件事是是否有观察者在监视已删除的节点。如果没有,那么上面的代码很好。如果是这样,您将需要更改从数据源中删除该行的位置以及何时重新加载 tableView。

【讨论】:

  • 我会进行重组,非常感谢!
猜你喜欢
  • 1970-01-01
  • 2018-05-13
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多