How to retrieve a list in Firebase database folder? - ios

I have a folder in my Database called "Cars", within the folder is a list of car brands, I want to retrieve all the brands and put it in a UITableView. Then when you press on a brand it will show the models of the brand. I have a trouble retrieving the list of cars at the moment. This is the screenshot of my Database and my code for the view controller.
import UIKit
import Firebase
import FirebaseDatabase
import SDWebImage
struct carStruct {
let cars : String!
}
class CarMakeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var cars = [carStruct]()
override func viewDidLoad() {
super.viewDidLoad()
let ref = Database.database().reference().child("Cars")
ref.observeSingleEvent(of: .value, with: { snapshot in
print(snapshot.childrenCount)
for rest in snapshot.children.allObjects as! [DataSnapshot] {
guard let value = rest.value as? Dictionary<String,Any> else { continue }
guard let make = value["Cars"] as? String else { continue }
let cars = carStruct(cars: make)
self.cars.append(cars)
}
self.cars = self.cars.reversed(); self.tableView.reloadData()
})
}
#IBOutlet weak var tableView: UITableView!
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cars.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellMake")
let label1 = cell?.viewWithTag(21) as! UILabel
label1.text = cars[indexPath.row].cars
return cell!
}
}

I think you should make another struct for holding data that is inside of the model of the car (so, for this struct you should dig little bit deeper). As for retrieving data now, I suggest you to read this article, which helped me a lot not long ago.

Related

Trouble passing the data from multiple selected tableview cells initially populated from Realm into another VC tableview. Swift

I have been at this for a few days now, what I am trying to do is to be able to select 5 cells (previous populated by a realm database). Any help on this would be really appreciated.
Thanks Mark
The following is my current code as is relates to the Segue to pass the data. I think I have edited the code down to the key elements. Let me know if you need any other information.
Edits Made - based on the suggestion made below. I took a step back and approached the problem differently, and developed a solution. I have updated the code below to reflect my working solution. Hope this helps someone else in the future. Cheers Mark
Primary VC
import UIKit
import RealmSwift
class ExercisesSelectionTimed: UITableViewController{
var realm = try! Realm()
var exercises : Results<ExercisesModel>?
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//populates the Realm Data with the default list
exercises = realm.objects(ExercisesModel.self)
tableView.allowsMultipleSelection = true
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return exercises?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExercisesAddedTableViewCell", for: indexPath) as! ExercisesAddedTableViewCell
// get the specific exercise in the array
let exercise = exercises?[indexPath.row]
cell.exercisenameLabel.text = exercise?.name
cell.equipmentnameLabel.text = exercise?.equipment
return cell
}
private func registerTableViewCells() {
let textFieldCell = UINib(nibName: "ExercisesAddedTableViewCell",bundle: nil)
self.tableview.register(textFieldCell,forCellReuseIdentifier: "ExercisesAddedTableViewCell")
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch (timerSelected) {
case "FGB":
//User needs to select 5 exercises to populate the FGB timer on the next VC
if let selectedRows = tableView.indexPathsForSelectedRows {
//lets the user select 5 cells
if selectedRows.count == 5 {
performSegue(withIdentifier: K.FGB, sender: self)
}
}
default : print ("error")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (timerSelected) {
case "FGB":
if let selectedRows = tableView.indexPathsForSelectedRows {
let selected = selectedRows.map{exercises?[$0.row]}
let destinationVC = segue.destination as! FBGTimerVCTable
destinationVC.selectedExercise = selected
}
default : print ("error")
}
}
}//last bracket in Class
The target for the data
import UIKit
import RealmSwift
class FBGTimerVCTable: HeartRateMonitorBrain{
var realm = try! Realm()
var selectedExercise = [ExercisesModel?]()
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}//last bracket in Class
extension FBGTimerVCTable: UITableViewDataSource{
//setup tableview
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExercisesAddedTableViewCell", for: indexPath) as! ExercisesAddedTableViewCell
//get the specific 5 exercises selected in the ExercisesSelectionTimed VC
cell.exercisenameLabel.text = selectedExercise[indexPath.row]?.name
cell.equipmentnameLabel.text = selectedExercise[indexPath.row]?.equipment
return cell
}
private func registerTableViewCells() {
let textFieldCell = UINib(nibName: "ExercisesAddedTableViewCell",bundle: nil)
self.tableview.register(textFieldCell,forCellReuseIdentifier: "ExercisesAddedTableViewCell")
}
}//last bracket in Class Extension
Realm
import RealmSwift
class ExercisesModel : Object {
#objc dynamic var name : String = ""
#objc dynamic var equipment : String = ""
}

Firebase data not displaying in tableview in xcode

I have been trying to retrieve profile data from firebase realtime database and displaying it in a table view, so far when I run the simulator the tabelview shows up blank and Failed : error 0:50 [50] shows up. I am pretty new to swift and am not sure what the problem is.
Here is my code:
import UIKit
import FirebaseDatabase
import FirebaseStorage
import FirebaseAuth
class userViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return profileData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "firstName_cell",
for: indexPath)
self.tableView.reloadData()
cell.textLabel?.text = self.profileData[indexPath.item]
return cell
}
var profileData = [String]()
let storageRef = Storage.storage().reference()
var databaseRef = Database.database().reference()
var ref: DatabaseReference?
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
//let userID = Auth.auth().currentUser?.uid
ref?.child("users").observeSingleEvent( of: .childAdded, with: { (snapshot) in
let profile = snapshot.value as? String
if let actualProfile = profile{
self.profileData.append(actualProfile)
print(self.profileData)
self.tableView.reloadData()
}
}) { (error) in
print(error.localizedDescription)
}
}
}
Don’t add reloadData() in cellForRow method.... it will become infinite loop .. so remove self.tableView.reloadData() from cellForRow method
You try to reload your tableView while its reloading.
You should not call tableView.reloadData() in tableView(_:cellForRowAt:) method or any other UITableViewDataSource method that is called from same UITableView.

How to get the child from a parent in a parent child relationship for realm in swift

What i am trying to do is access a child when I have the parent in realm. In this example I have a simple table view that I want to populate with the child when accessing the parent. The part I am struggling with is trying to find the child when accessing the parent.
This is the viewController that i am trying to access the children:
import UIKit
import Realm
import RealmSwift
class OtherViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var otherTableView: UITableView!
var realm: Realm!
var realmedData = ""
var realmList: Results<Realmed> {
get {
return realm.objects(Realmed.self)
}
}
var realmTwoList: Results<RealmTwo> {
get {
return realm.objects(RealmTwo.self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
realm = try! Realm()
self.otherTableView.delegate = self
self.otherTableView.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var counted = realm.objects(RealmTwo.self).filter("realmLbl == %#", realmedData)
return counted.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
cell.otherLbl.text = "\(items.spanish)"
}
}
return cell
}
}
this is another method I tried for the cell for row at:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
cell.otherLbl.text = "\(items.spanish)"
}
}
return cell
}
this is the parent realm class:
import Foundation
import Realm
import RealmSwift
class Realmed: Object {
#objc dynamic var label = ""
#objc dynamic var romanNum = ""
#objc dynamic var txt = ""
let realmTwo = List<RealmTwo>()
override static func primaryKey() -> String {
return "label"
}
convenience init(label: String, romanNum: String, txt: String) {
self.init()
self.label = label
self.romanNum = romanNum
self.txt = txt
}
}
and this is the realm class for the child:
import Foundation
import UIKit
import Realm
import RealmSwift
class RealmTwo: Object {
#objc dynamic var realmLbl = String()
#objc dynamic var spanish = String()
#objc dynamic var french = String()
let realmed = LinkingObjects(fromType: Realmed.self, property: "realmTwo")
convenience init(realmLbl: String, spanish: String, french: String) {
self.init()
self.realmLbl = realmLbl
self.spanish = spanish
self.french = french
}
}
When I run this as is, the only thing that populates the tableview is the last value saved to realm.
In this example the children are the strings: "Uno" and "Un", and I want them both to populate the tableView, but the tableView is only populated by the last value in realm, in this case, "Un".
Through research I found out that it is because I am looping through the realm value to get the child. The problem with that is that the only way to get to the child is with the loop but then it can't populate a tableView. It seems like a lose-lose situation.
What I am curious about is how to access the child when you have a parent in realm so that I am able to populate a tableView.
If you need anything please ask. Thank you
i think I got something. I figured that what I needed was an array, and it seems that it is unwise to change List to an Array, so what i did was get the content from the List and put it in an array, since it is easier to put data in a tableview from an array.
This is the array that i created:
var realmArr = [String]()
and this is the cell for row at for the tableView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "otherCell", for: indexPath) as! OtherTableViewCell
var celledItem = realm.objects(Realmed.self)
for item in celledItem {
for items in item.realmTwo {
self.realmArr.append(items.spanish)
}
}
cell.otherLbl.text = "\(realmArr[indexPath.row])"
return cell
}
I am not sure if this is okay, but it is the only thing that I can think of.
Thank you for all the help.
Let me address this at a high level with a few code snippets. The question is using Objects so let's take a more concrete example of Person and Dog. In this example we have a list of Person Objects each one owning one dog. So we have a single direction relationship
First we have a Person and Dog class
class DogClass: Object {
#objc dynamic var name: String = ""
}
class PersonClass: Object {
#objc dynamic var name: String = ""
#objc dynamic var dog: DogClass?
}
Here's a viewController class that contains a tableView of people
class peopleVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
var peopleResults: Results<PersonClass>!
override func viewDidLoad() {
super.viewDidLoad()
let realm = RealmService //or however you talk to your realm
self.tableView.delegate = self
self.tableView.dataSource = self
self.peopleResults = realm.objects(PersonClass.self) //loads Person objects
self.tableView.reloadData() //shows the list
}
and within that class, the tableView delegate methods that populate our tableview and handle a tap on a row
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peopleResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath as IndexPath)
let row = indexPath.row
let person = self.peopleResults[row]
cell.textLabel?.text = person.name
return cell
}
//when a row is tapped we need to determine the row, which will be included
// in the indexPath property with indexPath.row
// From there get the object from the dataSource array via it's row index
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let row = indexPath.row
let person = self.peopleResults[row]
let dog = person.dog
//at this point you have the dog object and you could print the name
print(dog.name)
//or pass it to a detail view via a segue etc
}

FireBase is returning strings as nil

Man, UITableView's just do not want to work with me. I have been outputting strings to Firebase storage and I see the values stored. My problem is that I cannot output any of those strings into the UITableView. I just see a blank table view and when I go and try to see what is being outputted by thoughtObjects.thoughts it just says "nil." If anyone can help figure out what is wrong that would be appreciated. Thank you so much StackOverflow.
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var inputThoughtTextField: UITextField!
#IBOutlet weak var successfulUploadLbl: UILabel!
#IBOutlet weak var tableView: UITableView!
var refThoughts: DatabaseReference!
var thoughtList = [ThoughtModel]()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return thoughtList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
//creating a cell using the custom class
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! VCTableViewCell
//the artist object
let thoughtObjects: ThoughtModel
//getting the artist of selected position
thoughtObjects = thoughtList[indexPath.row]
//adding values to labels
cell.wordCloud.text = thoughtObjects.thoughts
//print(cell.wordCloud.text)
//returning cell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
refThoughts = Database.database().reference().child("thoughts");
refThoughts.observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.thoughtList.removeAll()
//iterating through all the values
for thoughts in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let thoughtsObject = thoughts.value as? [String: AnyObject]
let thoughtText = thoughtsObject?["thoughts"]
let thoughtId = thoughtsObject?["id"]
//creating artist object with model and fetched values
let thoughtCreation = ThoughtModel(id: thoughtId as! String?, thoughts: thoughtText as! String?)
//appending it to list
self.thoughtList.append(thoughtCreation)
}
//reloading the tableview
self.tableView.reloadData()
}
})
}
#IBAction func buttonAddThought(_ sender: UIButton){
addThought()
}
func addThought(){
let key = refThoughts.childByAutoId().key
let thought = ["id": key,
"Thoughts": inputThoughtTextField.text! as String
]
refThoughts.child(key).setValue(thought)
successfulUploadLbl.text = "Thought Uploaded"
}
}

Populating TableView with retrieved data from Firebase with Swift 3

I've tried to retrieve data and set it into a tableview; I haven't really succeeded on this.
I want to fetch image and text into the tableView from firebase;
import UIKit
import Firebase
class HomePageViewController: UIViewController, UITableViewDelegate {
#IBOutlet weak var homePageTableView: UITableView!
var ref: DatabaseReference!
var imageFiles = [Data]()
var price = [String]()
var refHandle:UInt!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
fetchUsers()
func fetchUsers() {
refHandle = ref.child("Users").observe(.childAdded, with: { (<#DataSnapshot#>) in
if let retrivedData = DataSnapshot.value(String : AnyObject) {
???
}
})
I'm aware of this is unfinished but I have no clue of how to continue from this point. How do I set it to the table??? and how Do I retrieve the data correctly.
Can't find any documentation about this with the newest update firebase SDK and swift 3.0
The best practice is to feed the retrieved data into model objects and supply to the table view.
This is how modal objects looks like:
class Person {
var firstname: String
var lastname: String
init(firstname: String, lastname: String) {
self.firstname = firstname
self.lastname = lastname
}
}
Now you have to feed the JSON data you got from firebase to this model objects. Once your model object is ready, you have to load the tableview. Tableview has data source methods. Use them to show how to populate data in tableview.
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return modelObjectsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell")!
let modelObject = self.modelObjectsArray[indexPath.row] as! Person
cell.textLabel?.text = modelObject.firstname
return cell
}

Resources