Button only works when tapped twice - swift

I have two buttons that each have a different segue to a different view controller, which is only triggered if certain conditions are met. For some reason, one of the buttons works fine, the other button has to be tapped twice in order for it to segue to the next view controller. The strange part is that the code for both buttons and segue if conditions are copied and pasted and slightly modified to go to their respective vcs. How can I get both buttons to work on the first tap?
So far I've tried:
reordering the button functions
reordering the segue functions
deleting/reconnecting the button
deleting/reconnecting the button
I believe it has something to do with the following code because when I remove it, this behavior is gone and a different but similar feature in the app with virtually the same code (minus the part below) works just fine. I do need it however due to testing for nil/errors:
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
return nextButton
}
Here is the code
import UIKit
class bathShowerMeasurementViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
}
var nextButton = false
#IBOutlet weak var inchesButton: UIButton!
#IBAction func inches(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
}
#IBOutlet weak var unitError: UILabel!
#IBOutlet weak var centimeterButton: UIButton!
#IBAction func centimeter(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
}
#IBOutlet weak var length: UITextField!
#IBOutlet weak var lenghtError: UILabel!
#IBOutlet weak var width: UITextField!
#IBOutlet weak var widthError: UILabel!
#IBOutlet weak var height: UITextField!
#IBOutlet weak var heightError: UILabel!
#IBAction func showerCalc(_ sender: UIButton) {
let widthTub = Double(width.text!)
let lengthTub = Double(length.text!)
let heightTub = Double(height.text!)
var enableNextButton = true
if widthTub == nil || widthTub == 0.0 {
widthError.text = "Enter Width"
enableNextButton = false
}
if heightTub == nil || heightTub == 0.0 {
heightError.text = "Enter Height"
enableNextButton = false
}
if lengthTub == nil || lengthTub == 0.0 {
lenghtError.text = "Enter Length"
enableNextButton = false
}
switch (inchesButton.isSelected, centimeterButton.isSelected) {
case (false, false):
unitError.text = "Please Select A Unit"
enableNextButton = false
case (true, true):
unitError.text = "Only Select One Unit"
enableNextButton = false
default: break
}
nextButton = enableNextButton
}
#IBAction func goToShower(_ sender: UIButton) {
let widthTub = Double(width.text!)
let lengthTub = Double(length.text!)
let heightTub = Double(height.text!)
var enableNextButton = true
if widthTub == nil || widthTub == 0.0 {
widthError.text = "Enter Width"
enableNextButton = false
}
if heightTub == nil || heightTub == 0.0 {
heightError.text = "Enter Height"
enableNextButton = false
}
if lengthTub == nil || lengthTub == 0.0 {
lenghtError.text = "Enter Length"
enableNextButton = false
}
switch (inchesButton.isSelected, centimeterButton.isSelected) {
case (false, false):
unitError.text = "Please Select A Unit"
enableNextButton = false
case (true, true):
unitError.text = "Only Select One Unit"
enableNextButton = false
default: break
}
nextButton = enableNextButton
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
return nextButton
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let bathLength = Double(length.text!)
let bathWidth = Double(width.text!)
let bathHeight = Double(height.text!)
let water = Double(bathLength! * bathWidth! * bathHeight!)
if (segue.identifier == "showerCalc") {
if inchesButton.isSelected == true{
let bathWater = water / 231
let destinationVC = segue.destination as! showerFillMethodViewController
destinationVC.bathFlow = String(bathWater)
}
if centimeterButton.isSelected == true{
let bathWater = water / 3785.41
let destinationVC = segue.destination as! showerFillMethodViewController
destinationVC.bathFlow = String(bathWater)
}
}
if (segue.identifier == "showerTool") {
if inchesButton.isSelected == true{
let bathWater = water / 231
let destinationVC = segue.destination as! showerFlowMainViewController
destinationVC.bathFlow = String(bathWater)
}
if centimeterButton.isSelected == true{
let bathWater = water / 3785.41
let destinationVC = segue.destination as! showerFlowMainViewController
destinationVC.bathFlow = String(bathWater)
}
}
}
}

Related

Swift: Why can I pass info from one IBAction to another, but not to a function

I am trying to get the values for splitValue and tipPercent into the getSettings() at the bottom. Why can I get the values for both of those in the IBAction calculatePressed, but when I try to get the values into the function the value is nil. I am sooo confused. Thank you for the help!
#IBOutlet weak var billTextField: UITextField!
#IBOutlet weak var zeroPctButton: UIButton!
#IBOutlet weak var tenPctButton: UIButton!
#IBOutlet weak var twentyPctButton: UIButton!
#IBOutlet weak var splitNumberLabel: UILabel!
var tipChosen = ""
var totalPerPerson = ""
var tipPercent = ""
var splitValue = ""
#IBAction func tipChanged(_ sender: UIButton) {
tipPercent = sender.currentTitle!
if sender.isSelected == true {
return
}
zeroPctButton.isSelected = false
tenPctButton.isSelected = false
twentyPctButton.isSelected = false
sender.isSelected = true
if sender.currentTitle == "0%" {
tipChosen = "0.00"
} else if sender.currentTitle == "10%" {
tipChosen = "0.10"
} else if sender.currentTitle == "20%" {
tipChosen = "0.20"
}
billTextField.endEditing(true)
}
#IBAction func stepperValueChanged(_ sender: UIStepper) {
splitValue = String(Int(sender.value))
splitNumberLabel.text = String(Int(sender.value))
}
#IBAction func calculatePressed(_ sender: UIButton) {
let bill = Float(billTextField.text!)!
let tip = Float(tipChosen)!
let tax = bill * tip
let splitNumber = Float(splitNumberLabel.text!)
let total = (bill + tax) / Float(splitNumber!)
totalPerPerson = "$\(String(format: "%.2f", total))"
performSegue(withIdentifier: "goToTotal", sender: self)
}
func getSettings() -> String {
return "Split between \(splitValue) people, with a \(tipPercent) tip."
}
Ok, sorry it took me a bit, but I finally think I understand what I did.
class CalculatorViewController: UIViewController {
var tip = 0.0
var finalBill = ""
var split = 2
#IBOutlet weak var billTextField: UITextField!
#IBOutlet weak var zeroPctButton: UIButton!
#IBOutlet weak var tenPctButton: UIButton!
#IBOutlet weak var twentyPctButton: UIButton!
#IBOutlet weak var splitNumberLabel: UILabel!
#IBAction func tipChanged(_ sender: UIButton) {
if sender.isSelected == false {
sender.isSelected = false
} else if sender.isSelected == true {
sender.isSelected = true
}
zeroPctButton.isSelected = false
tenPctButton.isSelected = false
twentyPctButton.isSelected = false
sender.isSelected = true
billTextField.endEditing(true)
}
#IBAction func stepperValueChanged(_ sender: UIStepper) {
splitNumberLabel.text = Int(sender.value).description
}
#IBAction func calculatePressed(_ sender: UIButton) {
if zeroPctButton.isSelected == true {
tip = 0.0
} else if tenPctButton.isSelected == true {
tip = 0.1
} else if twentyPctButton.isSelected == true {
tip = 0.2
}
print(tip)
let bill = Double(billTextField.text!)
split = Int(Double(splitNumberLabel.text!)!)
if billTextField.text != "" {
let billWithTip = (bill! * tip) + bill!
let billWithTipSplit = billWithTip / Double(split)
finalBill = String(format: "%.2f", billWithTipSplit)
print(billWithTip)
}
self.performSegue(withIdentifier: "getResults", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "getResults" {
let destinationVC = segue.destination as! ResultsViewController
destinationVC.finalBill = finalBill
destinationVC.split = split
destinationVC.tip = tip
}
}
}
class ResultsViewController: UIViewController {
#IBOutlet weak var totalLabel: UILabel!
#IBOutlet weak var settingsLabel: UILabel!
var tip = 0.0
var split = 2
var finalBill = ""
override func viewDidLoad() {
super.viewDidLoad()
totalLabel.text = "$\(finalBill)"
settingsLabel.text = "Split between \(Int(split)) people, with a \(Int(tip * 100))% tip"
}
#IBAction func recalculatePressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
I did what you suggested with the string and some minor calculations on the second view controller, changed the values of a few declared properties and got rid of the getSettings(). I was under the impression that I couldn't pass data without a return value from a function. Thank you for the help!

How can I use a variable outside a function, im looking to get the documentdata() variable into the answer buttons

Since I call the getdata() in the viewDidLoad function I cant get the variable documentdata out. Im trying to use the documentdata's data for the button. I know I need a return type for the get data as well, but I cant seem to get that. TLDR: im trying to get the value documentdata into another a whole other function. Thank you in advance for anyone who responded.
import UIKit
import Firebase
import FirebaseFirestore
class QuizViewController: UIViewController {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var answerButtonTwo: UIButton!
#IBOutlet weak var answerButtonOne: UIButton!
#IBOutlet weak var answerButtonThree: UIButton!
#IBOutlet weak var answerButtonFour: UIButton!
#IBOutlet weak var displayAnswerChoice: UILabel!
var isrun = false
var documentdata:[String:Any] = ["":""]
override func viewDidLoad(){
super.viewDidLoad()
setupElements()
getData()
}
func setupElements(){
answerButtonOne.setTitle("", for:.normal)
answerButtonTwo.setTitle("", for:.normal)
answerButtonThree.setTitle("", for:.normal)
answerButtonFour.setTitle("", for:.normal)
questionLabel.text = ""
displayAnswerChoice.text = ""
}
func getData() {
let db = Firestore.firestore()
db.collection("quizs").document("basketballQuiz").getDocument { (document,error) in
if error == nil{
print("cant get data")
}
if document != nil && document!.exists{
let documentdata = document!.data()
self.questionLabel.text = documentdata?["Question"] as? String
self.answerButtonOne.setTitle(documentdata?["Answer1"] as? String, for:.normal)
self.answerButtonTwo.setTitle(documentdata?["Answer2"] as? String, for:.normal)
self.answerButtonThree.setTitle(documentdata?["Answer3"] as? String, for:.normal)
self.answerButtonFour.setTitle(documentdata?["Answer4"] as? String, for:.normal)
}
}
}
#IBAction func AnswerOneTap(_ sender: Any) {
let rightAnswer:Int = documentdata["correctAnswer"] as! Int
if (rightAnswer == 1){
displayAnswerChoice.text = "Correct"
displayAnswerChoice.backgroundColor = UIColor(named: "Green")
}
}
#IBAction func AnswerTwoTap(_ sender: Any) {
let rightAnswer:Int = documentdata["correctAnswer"] as! Int
if (rightAnswer == 2){
displayAnswerChoice.text = "Correct"
displayAnswerChoice.backgroundColor = UIColor(named: "Green")
}
}
#IBAction func AnswerThreeTap(_ sender: Any) {
let rightAnswer:Int = documentdata["correctAnswer"] as! Int
if (rightAnswer == 3){
displayAnswerChoice.text = "Correct"
displayAnswerChoice.backgroundColor = UIColor(named: "Green")
}
}
#IBAction func AnswerFourTap(_ sender: Any) {
let rightAnswer:Int = documentdata["correctAnswer"] as! Int
if (rightAnswer == 4){
displayAnswerChoice.text = "Correct"
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
Just assign the received documentdata to the property documentdata
if let documentdata = document?.data() {
self.documentdata = documentdata
self.questionLabel.text = documentdata["Question"] as? String
self.answerButtonOne.setTitle(documentdata["Answer1"] as? String, for:.normal)
self.answerButtonTwo.setTitle(documentdata["Answer2"] as? String, for:.normal)
self.answerButtonThree.setTitle(documentdata["Answer3"] as? String, for:.normal)
self.answerButtonFour.setTitle(documentdata["Answer4"] as? String, for:.normal)
}

how to filter data with multiple buttons using delegate?

The Delegate that I am using is used to filter out the specified category using a delegate when a button is pressed in the FilterVC
what im struggling with is setting up buttons in the FilterVC so that filter works in the HomeVC
ive noticed that issue might be in my FilterVC when using the delegate in the #IBAction func acceptSelections where im getting the error Cannot convert value of type 'RoundButton?' to expected argument type 'String?' when calling the buttons when using the delegate to control which category
import UIKit
import Firebase
import FirebaseFirestore
class HomeViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet var activeFiltersStackView: UIStackView!
#IBOutlet var stackViewHeightConstraint: NSLayoutConstraint!
#IBOutlet var jewelryFilterLbl: UILabel!
#IBOutlet var hatFilterLbl: UILabel!
#IBOutlet var shoeFilterLbl: UILabel!
#IBOutlet var apparelFilterLbl: UILabel!
#IBOutlet var gearFilterLbl: UILabel!
private lazy var baseQuery: Query = {
return Firestore.firestore().collection("products").limit(to: 50)
}()
fileprivate var query: Query?
lazy private var filters: (navigationController: UINavigationController,
filtersController: FilterViewController) = {
return FilterViewController.fromStoryboard(delegate: self)
}()
#IBAction func didTapClearBtn(_ sender: Any){
filters.filtersController.clearFilters()
controller(filters.filtersController, didSelectCategory: nil, sativa: nil, indica: nil, hybrid: nil, gear: nil)
}
var productSetup: [ProductList] = []
var products: ProductList?
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
// arranges products by store nearest you
fetchProducts { (products) in
self.productSetup = products.sorted(by: { $0.itemName < $1.itemName })
self.productListTableView.reloadData()
}
}
// fetches Firebase Data
func fetchProducts(_ completion: #escaping ([ProductList]) -> Void) {
let productQuery = Firestore.firestore().collection("products").limit(to: 50)
productQuery.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
}
// shows Firestore data in log (not neccessary code just used to be seen in logs)
productQuery.getDocuments { (snapshot, error) in
if let error = error {
print("Oh no! Got an error! \(error.localizedDescription)")
return
}
guard let snapshot = snapshot else { return }
let allDocuments = snapshot.documents
for productDocument in allDocuments {
print("I have this product \(productDocument.data())")
}
}
}
}
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as?
HomeCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
return cell
}
}
extension HomeViewController: FiltersViewControllerDelegate{
func query(withCategory jewelry: String?, hat: String?, shoe: String?, gear: String?, apparel: String?) -> Query {
if jewelry == nil && hat == nil && shoe == nil && gear == nil && apparel == nil {
stackViewHeightConstraint.constant = 0
activeFiltersStackView.isHidden = true
} else {
stackViewHeightConstraint.constant = 44
activeFiltersStackView.isHidden = false
}
var filtered = baseQuery
// Sort and Filter data
if let jewelry = jewelry, !jewelry.isEmpty {
filtered = filtered.whereField("category", isEqualTo: jewelry)
}
if let hat = hat, ! hat.isEmpty {
filtered = filtered.whereField("category", isEqualTo: hat)
}
if let shoe = shoe, !shoe.isEmpty {
filtered = filtered.whereField("category", isEqualTo: shoe)
}
if let gear = gear, !gear.isEmpty {
filtered = filtered.whereField("category", isEqualTo: gear)
}
if let apparel = apparel, !apparel.isEmpty {
filtered = filtered.whereField("category", isEqualTo: apparel)
}
return filtered
}
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: String?,
hat: String?,
shoe: String?,
gear: String?,
apparel: String?) {
if jewelry == nil && hat == nil && shoe == nil && gear == nil && apparel == nil {
stackViewHeightConstraint.constant = 0
activeFiltersStackView.isHidden = true
} else {
stackViewHeightConstraint.constant = 44
activeFiltersStackView.isHidden = false
}
let filtered = query(withCategory: jewelry, hat: hat, shoe: shoe, gear: gear, apparel: apparel)
if let jewelry = jewelry, ! jewelry.isEmpty {
jewelryFilterLbl.text = jewelry
jewelryFilterLbl.isHidden = false
} else {
jewelryFilterLbl.isHidden = true
}
if let hat = hat, ! hat.isEmpty {
hatFilterLbl.text = hat
hatFilterLbl.isHidden = false
} else {
hatFilterLbl.isHidden = true
}
if let shoe = shoe, ! shoe.isEmpty {
shoeFilterLbl.text = shoe
shoeFilterLbl.isHidden = false
} else {
shoeFilterLbl.isHidden = true
}
if let gear = gear, !gear.isEmpty {
gearFilterLbl.text = gear
gearFilterLbl.isHidden = false
} else {
gearFilterLbl.isHidden = true
}
if let apparel = apparel, ! apparel.isEmpty {
apparelFilterLbl.text = apparel
apparelFilterLbl.isHidden = false
} else {
apparelFilterLbl.isHidden = true
}
query = filtered
}
}
import UIKit
import Firebase
protocol FiltersViewControllerDelegate: NSObjectProtocol {
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: String?,
hat: String?,
shoe: String?,
gear: String?,
apparel: String?)
}
class FilterViewController: UIViewController {
#IBOutlet weak var jewelryBtn: RoundButton!
#IBOutlet weak var hatBtn: RoundButton!
#IBOutlet weak var shoeBtn: RoundButton!
#IBOutlet weak var gearBtn: RoundButton!
#IBOutlet weak var apparelBtn: RoundButton!
static func fromStoryboard(delegate: FiltersViewControllerDelegate? = nil) ->
(navigationController: UINavigationController, filtersController: FilterViewController) {
let navController = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "FiltersViewController")
as! UINavigationController
let controller = navController.viewControllers[0] as! FilterViewController
controller.delegate = delegate
return (navigationController: navController, filtersController: controller)
}
weak var delegate: FiltersViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func filterSelect(_ sender: Any) {
if let button : UIButton = sender as? UIButton
{
button.isSelected = !button.isSelected
if (button.isSelected)
{
button.backgroundColor = .green
}
else
{
button.backgroundColor = .gray
}
}
}
func clearFilters() {
apparelBtn.isSelected = false
jewelryBtn.isSelected = false
shoeBtn.isSelected = false
hatBtn.isSelected = false
gearBtn.isSelected = false
}
#IBAction func closeFilter(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func acceptSelections(_ sender: Any) {
delegate?.controller(self, //Problem integrating the buttons to get the correct category
didSelectCategory: jewelryBtn,
hat: hatBtn,
shoe: shoeBtn,
gear: gearBtn,
apparel: apparelBtn)
dismiss(animated: true)
}
}
As the filter functionality is pure boolean I recommend to just return the isSelected values of the buttons
protocol FiltersViewControllerDelegate: NSObjectProtocol {
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: Bool,
hat: Bool,
shoe: Bool,
gear: Bool,
apparel: Bool)
}
And call it
#IBAction func acceptSelections(_ sender: Any) {
delegate?.controller(self,
didSelectCategory: jewelryBtn.isSelected,
hat: hatBtn.isSelected,
shoe: shoeBtn.isSelected,
gear: gearBtn.isSelected,
apparel: apparelBtn.isSelected)
dismiss(animated: true)
}
It seems to be a multiple choice selection so you have to combine the options in the query.

how to save the state of radio button?

i am trying to save the state of my radio button but it doesn't working for me any idea how to do that? i am using userdefaults for that now
class WTSettingsVC: UIViewController {
#IBOutlet weak var checkBttn: DLRadioButton!
#IBOutlet weak var checkBttn2: DLRadioButton!
var switchON : Bool = false
var button : Bool = false
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
checkBttn.isSelected = UserDefaults.standard.bool(forKey: "issaved")
checkBttn2.isSelected = UserDefaults.standard.bool(forKey: "issaved")
}
override func viewWillAppear(_ animated: Bool) {
super .viewWillAppear(animated)
self.setCommonNavigationBar(title: "Settings", largeTitle: true, tranpernt: false, tint: WTConstant.LMColors.greenTheme, fontColor: .white)
checkBttn?.isEnabled = UserDefaults.standard.bool(forKey: "switchState")
checkBttn?.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
}
#IBAction func bttnAction(_ sender: DLRadioButton) {
if sender.tag == 1 {
sender.isEnabled = true
switchON = true
defaults.set(switchON, forKey: "switchON")
}else if sender.tag == 2{
sender.isEnabled = true
switchON = false
defaults.set(switchON, forKey: "switchON")
}
}
}
UserDefaults.standard.set(sender.isEnabled, forKey: "switchState")
UserDefaults.standard.synchronize()
}
}
Don't use the same key to store state of two buttons. And use same key for storing and retrieving the state of a button.
class WTSettingsVC: UIViewController {
#IBOutlet weak var checkBttn: DLRadioButton!
#IBOutlet weak var checkBttn2: DLRadioButton!
override func viewDidLoad() {
super.viewDidLoad()
checkBttn.isSelected = UserDefaults.standard.bool(forKey: "checkBttnSelected")
checkBttn2.isSelected = UserDefaults.standard.bool(forKey: "checkBttn2Selected")
checkBttn.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
checkBttn2.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
}
#IBAction func bttnAction(_ sender: DLRadioButton) {
if sender == checkBttn {
UserDefaults.standard.set(true, forKey: "checkBttnSelected")
UserDefaults.standard.set(false, forKey: "checkBttn2Selected")
}else if sender == checkBttn2 {
UserDefaults.standard.set(false, forKey: "checkBttnSelected")
UserDefaults.standard.set(true, forKey: "checkBttn2Selected")
}
}
}
It seems that your code is pretty obviously nested improperly. For example, the following code isn't actually executing in the bttnAction function:
UserDefaults.standard.set(sender.isEnabled, forKey: "switchState")
UserDefaults.standard.synchronize()
This code needs to be placed within the curly bracket above it. Try rewriting your code similarly to this:
class WTSettingsVC: UIViewController {
#IBOutlet weak var checkBttn: DLRadioButton!
#IBOutlet weak var checkBttn2: DLRadioButton!
var switchON : Bool = false
var button : Bool = false
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
checkBttn.isSelected = UserDefaults.standard.bool(forKey: "issaved")
checkBttn2.isSelected = UserDefaults.standard.bool(forKey: "issaved")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setCommonNavigationBar(title: "Settings", largeTitle: true, tranpernt: false, tint: WTConstant.LMColors.greenTheme, fontColor: .white)
checkBttn?.isEnabled = UserDefaults.standard.bool(forKey: "switchState")
checkBttn?.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
}
#IBAction func bttnAction(_ sender: DLRadioButton) {
if sender.tag == 1 {
sender.isEnabled = true
switchON = true
defaults.set(switchON, forKey: "switchON")
} else if sender.tag == 2 {
sender.isEnabled = true
switchON = false
defaults.set(switchON, forKey: "switchON")
}
UserDefaults.standard.set(sender.isEnabled, forKey: "switchState")
UserDefaults.standard.synchronize()
}
}
Because these lines of code were outside of the closing bracket for that function, the lines weren't actually included in any function and, thus, would never be called.

How do I set my variable correctly to a value on Firebase and not have it reset the progress?

Everytime I leave this ViewController and then come back the quiz starts back to question 1. I want it to resume from where I left off.
I believe why it keeps resetting to zero is because my initial "questionNumber" is set to 0 but I'm not sure how to set its value to the value in Firebase correctly. I get error after error. I've tried so many different ways but none of them seem to work and resume from where I left off.
Thanks for your help! PLEASE help me!
class CryptoViewController: UIViewController {
var questionList = CryptoBank()
var score = 0
var pickedQuestion = 0
var uid = FIRAuth.auth()?.currentUser?.uid
var questionNumber = 0
#IBOutlet weak var questionViewer: UILabel!
#IBOutlet weak var choiceOne: UIButton!
#IBOutlet weak var choiceTwo: UIButton!
#IBOutlet weak var choiceThree: UIButton!
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var questionNumberView: UILabel!
#IBOutlet weak var progressBarView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
choiceOne.titleLabel?.textAlignment = NSTextAlignment.center
choiceTwo.titleLabel?.textAlignment = NSTextAlignment.center
choiceThree.titleLabel?.textAlignment = NSTextAlignment.center
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.view.backgroundColor = .clear
update()
}
#IBAction func buttonPressed(_ sender: AnyObject) {
if sender.tag == 1 {
pickedQuestion = 1}
else if sender.tag == 2 {
pickedQuestion = 2}
else if sender.tag == 3 {
pickedQuestion = 3}
checkAnswer()
questionNumber += 1
nextQuestion()
}
func checkAnswer(){
let correctAnswer = questionList.cryptoBank[questionNumber].answer
if pickedQuestion == correctAnswer {
score += 1
}else{
print("Wrong Answer")
}
}
func updateFirebase(){
let ref = FIRDatabase.database().reference()
guard let uid = FIRAuth.auth()?.currentUser!.uid else{
return}
ref.child("Users").child(uid).child("Cryptoquiz").child("Question Number").setValue(questionNumber)
ref.child("Users").child(uid).child("Cryptoquiz").child("Score").setValue(score)
}
func nextQuestion(){
if questionNumber <= 9 {
update()
} else{
scoreLabel.text = "Score: \(score)"
let alert = UIAlertController(title: "Done!", message: "Would you like to restart?", preferredStyle: .alert)
let restartAction = UIAlertAction(title: "Restart", style: .default, handler: { (UIAlertAction) in
self.startAgain()
})
alert.addAction(restartAction)
present(alert, animated: true, completion: nil)
}}
func update(){
let nextQuest = questionList.cryptoBank[questionNumber]
questionViewer.text = nextQuest.question
choiceOne.setTitle(nextQuest.choice1, for: .normal)
choiceTwo.setTitle(nextQuest.choice2, for: .normal)
choiceThree.setTitle(nextQuest.choice3, for: .normal)
scoreLabel.text = "Score: \(score)"
questionNumberView.text = "Question: \(questionNumber + 1)"
progressBarView.frame.size.width = (view.frame.size.width/9) * CGFloat(questionNumber + 1)
updateFirebase()
}
}
You can save your progress in UserDefaults in viewDidDisappear() like this:
UserDefaults.standard.set(questionNumber, forKey: "questionNumber")
And then every time you open your view, in viewDidLoad() or in viewDidAppear() you update your questionNumber like this:
let questionNumberSaved = UserDefaults.standard.integer(forKey: “questionNumber”) ?? 0
questionNumber = questionNumberSaved
Then after doing this you call your updateFirebase() method