ios - 从 FIREBASE 嵌套的子节点中捕获信息到一个数组中,并将其传递给下一个 ViewController XCODE

标签 ios swift firebase firebase-realtime-database

FIREBASE image of JSON tree with nested QUESTIONS

func loadTitles(){

    databaseHandle = ref?.child("Titles").observe(.childAdded) { (snapshot: DataSnapshot) in

        if let dict = snapshot.value as? [String: Any]{

            let titleName = dict["Name"] as! String
            let directorName = dict["Director"] as! String
            let releaseDate = dict["Release"] as! String
            let titleImage = dict["TitleImage"] as? String
            let titleRating = dict["Rating"] as? Int

            let title = Title(titleName: titleName, titleImage: titleImage, directorName: directorName, releaseDate: releaseDate, titleRating: titleRating)

            self.Titles.append(title)
            self.tableView.reloadData()
        }
    }
}

这段代码是我如何建模从数据库中获取的初始 JSON。这一切在 tableview 中都可以正常工作。它还有一个包含许多问题的 child 。例如,参见图像。 enter image description here我正在制作一个问答游戏。很简单。

使用 XCODE 9、Swift 4 和 FIREBASE。

一切都在使用硬编码数据,但自从切换到 FIREBASE 后,我一直无法让它按原样运行。

我当前的问题是在用户导航时在不同屏幕上使用同一快照的不同方面。

我已经对此进行了研究,但我的问题只解决了一半。我知道如何从 FIREBASE 捕获快照,但我实际想做的是:

  1. 我有一个名为 TITLE 的子项,其中包含标题详细信息的值。每个 TITLE 都有一个名为 QUESTIONBANK 的子项,然后包含多个 QUESTION 子项,每个子项都有值:问题、答案、答案、答案等。因此,一个 TITLE 可以有很多问题,每个 QUESTION 都有自己的一组答案。

  2. 在表格 View 中,我通过快照抓取 TITLES 并显示它们。一切正常。我将它推送到一个数组并使用 TITLE 模型动态显示它们。我还设置了一个缓存助手,以允许在用户来回访问时在 session 期间保存它。

问题!

  1. 然后我想允许用户点击一个单元格并前往实际的琐事部分,并使用特定 TITLE 的问题库子项中的问题。即在下一页上创建一系列问题和答案,使用选择的标题作为问题库节点的引用,以使用特定于该标题的标题。

问题是,一旦我在一个页面上使用了 TITLE 的快照,我就无法返回并为用户选择的那个 TITLE 创建一个包含所有问题和答案的数组,而我们移至另一页。

我已经为此创建了模型,并且我知道它可以正常工作,因为我在设置 FIREBASE 并将所有硬编码数据替换为 FIREBASE 数据库、存储和身份验证之前为其硬编码数据。

这一直是一场斗争,因为我对这一切都很陌生,现在我遇到了这件最新的事情。我不想花几天或一周的时间来弄清楚。

感谢任何帮助!

最佳答案

让我从两个方面来回答这个问题。问题的具体答案,然后建议使用不同结构的方法。

给定一个与你几乎相同的电影结构

  "movies" : {
    "movie_id_0" : {
      "question_bank" : {
        "questions" : {
          "question_0" : {
            "correct_answer" : "HAL 9000",
            "question_text" : "Name of computer"
          }
        }
      },
      "title" : "2001, A Space Odyssey"
    },
    "movie_id_1" : {
      "question_bank" : {
        "questions" : {
          "question_0" : {
            "correct_answer" : "Ted Stryker",
            "question_text" : "Main character name"
          }
        }
      },
      "title" : "Airplane"
    }
  },

这是读取电影节点的代码,打印出每部电影的标题,然后是问题;为简洁起见,我只为每部电影做了一个,但如果有更多(问题_1、问题_2 等),这些也会打印出来。

let ref = self.ref.child("movies")
ref.observeSingleEvent(of: .value, with: { snapshot in
    if snapshot.exists() == true {

        for movieChild in snapshot.children { //this will iterate over every movie node
            let movieSnap = movieChild as! DataSnapshot //each movie is it's own snapshot

            let movieDict = movieSnap.value as! [String: Any]
            let title = movieDict["title"] as! String
            print(title)

            let questionBank = movieSnap.childSnapshot(forPath: "question_bank")
            let questions = questionBank.childSnapshot(forPath: "questions")

            for questionChild in questions.children {
                let questionSnap = questionChild as! DataSnapshot
                let questionDict = questionSnap.value as! [String: Any]
                let question = questionDict["question_text"] as! String
                let answer = questionDict["correct_answer"] as! String
                print("  q: \(question)  a:\(answer)")
            }
        }
    } else {
        print("no snapshot found")
    }
})

和输出

2001, A Space Odyssey
  q: Name of computer  a:HAL 9000
Airplane
  q: Main character name  a:Ted Stryker

根据您的原始问题,上述代码将使您能够访问问题库中的问题。

让我们看看替代结构:

首先要注意的是 question_bank 有一个子问题,然后有子问题(q0、q1 等)。问题节点可以被删除并向上移动所有子节点

"movies" : {
  "movie_id_0" : {
    "question_bank" : {
      "question_0" : {
         "correct_answer" : "HAL 9000",
         "question_text" : "Name of computer"
       }
    },
  "title" : "2001, A Space Odyssey"
},

虽然这是一个非常深的结构,但查询和使用起来会非常复杂。这是一个更好的结构:

"movies" : {
   "movie_id_0" : {
      "title" : "2001, A Space Odyssey"
    },

"questions" : {
   "question_0"
      "for_movie_id": "movie_id_0"
      "correct_answer" : "HAL 9000",
      "question_text" : "Name of computer"
   "question_1"
      "for_movie_id": "movie_id_0"
      "correct_answer" : "Stanley Kubrick",
      "question_text" : "Directed by?"

这将允许查询 2001 年太空漫游的所有问题、HAL 9000 的所有答案以及斯坦利库布里克执导的所有电影。

我什至可以再走一步,在要提问的电影之间添加一个反比关系

"movies" : {
   "movie_id_0" : {
      "title" : "2001, A Space Odyssey"
      "questions": {
         "question_0": true
         "question_1": true
    },

让数据尽可能平坦是 Firebase 中的最佳实践。看看Denormalizing is Normal了解更多信息。

关于ios - 从 FIREBASE 嵌套的子节点中捕获信息到一个数组中,并将其传递给下一个 ViewController XCODE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47493078/

相关文章:

ios - 如何在 coreplot 中隐藏带有图例的折线图?

ios - 以最少的开销将缓冲区数据转换为 UInt8

android - 每次应用程序重新启动时避免登录屏幕

firebase - 仅限 Firebase 服务器访问 Google Cloud VM

ios - 在 XC UI 测试期间删除 TextView 中的文本?

objective-c - 将图像(或其他资源)添加到 Mac 或 iOS 框架

swift - 创建 Swift 属性

swift - IOS TableView 如何更新我的 TableView 中的元素

ios - 从字节中获取位的值 | swift 5

ios - Firebase 未通过 GTM 向 Google Analytics 发送相同数量的事件