Reputation: 3362
I am trying to create programmatic Radio Buttons
based on dynamic Firebase data. The number of Radio Buttons
is dependent on an integer value stored in Firebase, named numberOfChildren
.
The value I am receiving from Firebase is coming back nil
and I cannot figure out why. Any help on how to resolve this issue so that I can return an integer value would be appreciated:
import UIKit
import FirebaseDatabase
import DLRadioButton
class PollController: UIViewController {
@IBOutlet weak var passLabel: UILabel!
@IBOutlet weak var pollImage: UIImageView!
var ref: FIRDatabaseReference!
var pollRef: FIRDatabaseReference!
var pass = ""
var passedImageURL = ""
var posX = 0;
var posY = 0;
var numberOfChildren: Int!
let label2 = UILabel(frame: CGRect(x: 90, y: 160, width: 200, height: 70))
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
pollRef = ref.child("Polls").child(pass)
passLabel.text = pass
pollImage.sd_setImage(with: URL(string: passedImageURL), placeholderImage: UIImage(named: "test"))
pollRef.observe(FIRDataEventType.value, with: {(snapshot) in
self.numberOfChildren = Int(snapshot.childSnapshot(forPath: "answers").childrenCount)
self.passLabel.text = String(self.numberOfChildren)
print(self.numberOfChildren)
})
var buttons = [DLRadioButton]()
for x in 0..<self.numberOfChildren {
let firstRadioButton = self.createRadioButton(frame: CGRect(x: CGFloat(x)*32, y: self.view.center.y, width: 40.0, height: 20.0), title: String(x), color: UIColor.green)
firstRadioButton.tag = x
buttons.append(firstRadioButton)
self.view.addSubview(firstRadioButton);
}
let groupButtons = DLRadioButton()
groupButtons.otherButtons = buttons
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> DLRadioButton {
let radioButton = DLRadioButton(frame: frame);
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: UIControlState.normal);
radioButton.setTitleColor(color, for: UIControlState.normal);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;
radioButton.addTarget(self, action: #selector(self.logSelectedButton(_:)), for: UIControlEvents.touchUpInside);
return radioButton;
}
@objc private func logSelectedButton(_ sender: DLRadioButton){
print("Selected Button Tag = \(sender.tag) and Title \(sender.titleLabel?.text)")
}
}
Upvotes: 0
Views: 308
Reputation: 600131
The problem is in the way you nest the code. Firebase loads the data asynchronously, that's why you pass in a callback block: so that it can call your code block once the data has loaded. By the time you look over self.numChildren
that data hasn't loaded yet.
The solution is to move the code that requires numChildren
into the callback block.
pollRef.observe(FIRDataEventType.value, with: {(snapshot) in
self.numberOfChildren = Int(snapshot.childSnapshot(forPath: "answers").childrenCount)
self.passLabel.text = String(self.numberOfChildren)
var buttons = [DLRadioButton]()
for x in 0..<self.numberOfChildren {
let firstRadioButton = self.createRadioButton(frame: CGRect(x: CGFloat(x)*32, y: self.view.center.y, width: 40.0, height: 20.0), title: String(x), color: UIColor.green)
firstRadioButton.tag = x
buttons.append(firstRadioButton)
self.view.addSubview(firstRadioButton);
}
let groupButtons = DLRadioButton()
groupButtons.otherButtons = buttons
})
This way the loop is only invoked once numChildren
has been initialized from the database.
Upvotes: 1