Retrieve from firebase to multiple buttons in swift 3

北慕城南 提交于 2020-01-17 07:35:19

问题


I am trying to retrieve data from firebase and display into multiple buttons and label. After retrieving i am saving it into a dictionary. This is my model

import Foundation
import Firebase

    class QuestionModel: NSObject {

        var CorrectAnswer: String!
        var Question: String!
        var optionA: String!
        var optionB: String!
        var optionC: String!

        init(snapshot: FIRDataSnapshot) {
            if let snapshotDict = snapshot.value as? Dictionary<String, Any> {
                CorrectAnswer = snapshotDict["CorrectAnswer"] as? String
                Question = snapshotDict["Question"] as? String
                optionA = snapshotDict["optionA"] as? String
                optionB = snapshotDict["optionB"] as? String
                optionC = snapshotDict["optionC"] as? String
            }
        }
    }

My JSON

I tried some ways but it return me nil .I think coz of asynchronous firebase.

This is my code .

import Foundation
import UIKit
import Firebase
import FirebaseDatabase

class AnsweringQuestionViewController: UIViewController {

    @IBOutlet weak var qLabel: UILabel!
    @IBOutlet weak var buttonA: UIButton!
    @IBOutlet weak var buttonB: UIButton!
    @IBOutlet weak var buttonC: UIButton!
    @IBOutlet weak var correctAnswer: UIButton!

    //var buttons: [UIButton]! thinking of using button tags?

    var ref: FIRDatabaseReference!
    var questionModel : [QuestionModel] = []

    override func viewDidLoad(){
        super.viewDidLoad()
      //  FIRDatabase.database().persistenceEnabled = true
        ref = FIRDatabase.database().reference()
        db()
    }
    func db(){
        ref.child("Science").observe(.value, with: {
            snapshot in
            for child in snapshot.children {
                let user = QuestionModel.init(snapshot: (child as? FIRDataSnapshot)!)
                self.questionModel.append(user)
            }
         self.qLabel.text = self.questionModel[0].Question
        self.buttonA.setTitle("\(self.questionModel[0].CorrectAnswer)", for: UIControlState.normal)
        }, withCancel: nil)
        }
}

Pls bare with my code i am still learning. I don't have any idea where to go from here in displaying my data into multiple buttons and identifying which button is 'clicked' is the CorrectAnwer.

I would be very happy if you could reconstruct my code to a cleaner way if you want. Thank you :)


回答1:


Try this...

import FirebaseDatabase

class Question {

   var correctAnswer: String?
   var question: String?
   var optionA: String?
   var optionB: String?
   var optionC: String?

   init(snapshot: FIRDataSnapshot){
       if let snap = snapshot.value as? [String: String] {
           correctAnswer = snap["CorrectAnswer"]
           question = snap["Question"]
           optionA = snap["OptionA"]
           optionB = snap["OptionB"]
           optionC = snap["OptionC"]
       }
   }

}




import FirebaseDatabase
import UIKit

class ViewController: UIViewController {

   @IBOutlet weak var qLabel: UILabel!
   @IBOutlet weak var buttonA: UIButton!
   @IBOutlet weak var buttonB: UIButton!
   @IBOutlet weak var buttonC: UIButton!
   @IBOutlet weak var correctAnswer: UIButton!

   var fireRootRef: FIRDatabaseReference!
   var questions = [Question]()

   override func viewDidLoad() {
       super.viewDidLoad()
       fireRootRef = FIRDatabase.database().reference()
       fetchQuestions(inCategory: "Science")
   }


   func fetchQuestions(inCategory category: String){
       let questionsRef = fireRootRef.child(category)

       questionsRef.observe(.value, with: {(snapshot)-> Void in

           var allQuestions = [Question]()
           for child in snapshot.children {
               allQuestions.append(Question(snapshot: child as! FIRDataSnapshot))
           }
           self.questions = allQuestions
           self.reloadUI(withQuestions: self.questions)
       })
   }

   func reloadUI(withQuestions questions: [Question]){
       guard questions.count > 0 else {return}

        if let answerToQuestion1 = questions[0].correctAnswer, let wrongAnswer = questions[0].optionA, let wrongAnswer2 = questions[0].optionB, let wrongAnswer3 = questions[0].optionC {

            let randomOrderedAnswers = [answerToQuestion1, wrongAnswer, wrongAnswer2, wrongAnswer3].shuffled()

            buttonA.setTitle(randomOrderedAnswers[0], for: .normal)
            buttonB.setTitle(randomOrderedAnswers[1], for: .normal)
            buttonC.setTitle(randomOrderedAnswers[2], for: .normal)
            correctAnswer.setTitle(randomOrderedAnswers[3], for: .normal)//keep in mind the correctAnswer label wont always contain the actual correct answer now

        } else {
            print("failed to get value for one of the answes options")
        }

       if let questionText = questions[0].question {
           qLabel.text = questionText
       } else {
           qLabel.text = "failed to get question text"
       }
   }

}




    extension MutableCollection where Indices.Iterator.Element == Index {
/// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
            guard d != 0 else { continue }
            let i = index(firstUnshuffled, offsetBy: d)
            swap(&self[firstUnshuffled], &self[i])
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Iterator.Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}

update I've added extensions that allow you to shuffle the order of elements in an array so that you can set the answer labels "randomly" and the correct answer won't always be in the same place. The extension are courtesy of @NateCook from this question here

To know if the correct answer was selected just check if the text of the selected button is == to the correctAnswer property of the question, for example if buttonA.title(for: .normal)! == questions[0].correctAnswer {print("correct answer selected)"} . Just make sure to unwrap the optional value of buttonA.title(for: .normal) otherwise it will have the word "optional" before it and therefore won't be exactly equal to the correct answer text



来源:https://stackoverflow.com/questions/42841730/retrieve-from-firebase-to-multiple-buttons-in-swift-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!