将项目从Firebase加载到pickerview的问题 [英] issues loading items from firebase to a pickerview

查看:40
本文介绍了将项目从Firebase加载到pickerview的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经成功创建了QuestionModel类,该类从firebase中检索项目,例如Question,答案字符串和正确的问题.但是,现在我很难让这些项目从另一个班级进入选择器视图.就使用问题类从中检索数据而言,名为QuestionsViewController的类是我遇到的问题. QuestionModel类包含从Firebase检索数据.我在QuestionsViewController类的整个代码中都有执行错误.这主要是在尝试在pickverview和pickerview函数的代码之前设置itemlabel文本时发生的.

I have successfully created a QuestionModel class which retrieves items from firebase such, as a Question, string of answers and a correct question. I am however now having difficulty in terms of getting these items to go into a picker view from another class. The class called QuestionsViewController is where I am having an issue in terms of using the questions class to retrieve data from. The QuestionModel class contains retrieving data from firebase. I am having bad execution errors throughout the code in the QuestionsViewController class. This mainly occurs when trying to set the itemlabel text before the pickverview and code for the pickerview functions.

import Foundation
import Firebase
import FirebaseDatabase
import FirebaseAuth
import CoreData

class QuestionList
{
//properties
public static var Username: String = ""
private static var quiz = [Question]()

static func getDummyQuestions()->[Question]
{
    //create some dummy data for the model
    var ref: FIRDatabaseReference!
    var refHandle: UInt!
    ref = FIRDatabase.database().reference() //reference

    refHandle = ref.child("Questions").child("Q1").observe(.value,       with: { (snapshot)in
        if let dataDict = snapshot.value as? [String: Any] {

            if let quest = dataDict["Question"] as? String,
                let Answers = dataDict["Answers"] as? [String],
                let Correct = dataDict["Correct"] as? Int {
                quiz.append(Question(q: quest, a: Answers, c: Correct))
            }
            print (dataDict)
        }
    })
    return quiz
  } 
}


class Question {
  var quest:String
  var answers:[String]
  var correct:Int

  init(q: String, a:[String], c:Int)
  {
      quest = q
      answers = a
      correct = c
  }

  func isCorrectQuestion(itemSelected: String)->Bool {
      if (itemSelected == answers[correct]) {
          return true
      } else {
          return false
      }
  }
}

import UIKit
import Firebase
import FirebaseAuth

class QuestionsViewController: UIViewController, UIPickerViewDelegate {

@IBOutlet weak var usernamelabel: UILabel! //sets username label
@IBOutlet weak var Next: UIButton! //next button
@IBOutlet weak var itemLabel: UILabel! //item user has selected
@IBOutlet weak var Question: UILabel! //sets question label
@IBOutlet weak var pickerview: UIPickerView! //sets picker view

public var totalQuestions: Int = 0 //sets total question to 0
public var currentQuestion = 0  //sets current question to 0
public var totalCorrect: Int = 0 //sets totalcorrect to 0
var itemSelected: String = "" //item selected
var LabelText = String()
let Exam = QuestionList() //uses the questions class for instances
var Questions = QuestionList.getDummyQuestions()

var ref: FIRDatabaseReference!
var refHandle: UInt!

override func viewDidLoad() {
    super.viewDidLoad() //when the app is loaded

    ref = FIRDatabase.database().reference() //reference
    refHandle = ref.child("Questions").observe(.value, with: { (snapshot)in
        let dataDict = snapshot.value as! [String: AnyObject]
        print (dataDict)
    })
     usernamelabel.text = LabelText //username

    pickerview.delegate = self

    itemLabel.text = "" //loads the item label of whats selected
    itemSelected = QuestionList.getDummyQuestions()[currentQuestion].answers[0] //initially when loaded first item is selected
    Question.text = QuestionList.getDummyQuestions()[currentQuestion].quest
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1 //return one component from the picker
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
    return QuestionList.getDummyQuestions()[currentQuestion].answers.count  
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int,    forComponent component: Int) -> String?{
    return QuestionList.getDummyQuestions().  [currentQuestion].answers[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int){

    itemSelected = QuestionList.getDummyQuestions(). [currentQuestion].answers[row]
}

@IBAction func NextAction(_ sender: Any){

   currentQuestion = currentQuestion + 1 //moves onto next question and   increments

    if (QuestionList.getDummyQuestions()[currentQuestion].isCorrectQuestion(itemSelected: itemSelected)) {
        totalCorrect += 1
        itemLabel.text = String(totalCorrect) + "/" + String(totalQuestions)
    }

    if(currentQuestion < QuestionList.getDummyQuestions().count) {
        pickerview.reloadAllComponents()
        itemSelected = QuestionList.getDummyQuestions()[currentQuestion].answers[1]
        Question.text = QuestionList.getDummyQuestions() [currentQuestion].quest
    } else {
        pickerview.isHidden = true
        Question.text = "You have finished"
        Next.isHidden = true
    }
}

}

推荐答案

Firebase函数不会(也不应该)返回值,因为它们是异步的.

Firebase functions do not (and should not) return values as they are asynchronous.

因此,大多数情况下,返回测验行将失败,因为它将在Firebase有时间从服务器检索数据之前尝试返回数据.

So the return quiz line will fail most of the time as it will try to return data before Firebase has had time to retrieve it from the server.

使用Firebase进行编码时,数据仅在该函数后的闭包内部有效.因此,例如,这是不应该做的:

When coding with Firebase, data is only valid inside the closure following the function. So for example, this what NOT to do:

func someFunc() {
    ref.child("Questions").child("Q1").observe(.value, with: { snapshot in
      print(snap)
    })

    print(snap) //this will not print the snap as this line executes *before* the closure
}

以正确的方式进行操作;从Firebase检索数据,填充数组并刷新闭包中的tableview.

So doing it the right way; retrieve the data from Firebase, populate the array and refresh the tableview all within the closure.

static func populateArrayAndRefreshTableView()
{
    var ref: FIRDatabaseReference!= FIRDatabase.database().reference()
    let questionsRef = ref.child("Questions")

    questionsRef.child("Q1").observeSingleEvent(of: .value, with: { snapshot in
        if let dataDict = snapshot.value as? [String: Any] {
            let quest = dataDict["Question"] as? String,
            let Answers = dataDict["Answers"] as? [String],
            let Correct = dataDict["Correct"] as? Int {
            self.quizArray.append(Question(q: quest, a: Answers, c: Correct))
            self.tableView.reloadData()
        }
    })
  } 
}

还请注意,原始代码使用的是watch(.value).这将使观察员附加到ref上,如果问题发生更改,则将调用代码.看起来不应该是这种行为,因此使用observeSingleEvent会在不添加观察者的情况下调用一次.

Also note that the original code was using observe(.value). That will leave an observer attached to the ref and if the question changes, the code will be called. It doesn't look like that should be the behavior so using observeSingleEvent will call it once without adding an observer.

最后-您可能需要重新考虑如何在结构中命名节点.通常最好的做法是将节点名称键与其包含的数据解除关联.

Finally - you may want to re-consider how the nodes are named in your structure. It's often best practice to disassociate node name keys from the data they contain.

questions
   -UYiuokoksokda
      question: "What significant contribution to bioengineering was made on the Loonkerian outpost on Klendth?"
      correct_answer: answer_1
      answers:
        answer_0: "Left handed smoke shifter"
        answer_1: "The universal atmospheric element compensator"
        answer_2: "Warp coil nullification amplifier"
        answer_3: "H.A.L. 9000"
   -YY8jioijasdjd
      question: "What is Kiri-kin-tha's first law of metaphysics?"
      correct_answer: answer_2
      answers:
        answer_0: "No matter where you go, there you are"
        answer_1: "Only people with sunroofs use them"
        answer_2: "Nothing unreal exists"
        answer_3: "Gravity is heavy"

UYiuokoksokda键是使用childByAutoId()创建的.

The keys, UYiuokoksokda, are created with childByAutoId().

如果您需要查询答案,您甚至可能希望将它们规范化为它们自己的节点,并使用问题关键字作为答案的节点关键字,或者使用问题关键字保留子节点.

If you need to query answers you may want to even denormalize them into their own node and use the question key as the node key for the answers or keep a child node with the question key.

这篇关于将项目从Firebase加载到pickerview的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆