Retrieve from firebase to multiple buttons in swif

2019-09-12 12:11发布

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

enter image description here

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条回答
时光不老,我们不散
2楼-- · 2019-09-12 12:47

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

查看更多
登录 后发表回答