I want to display data from firebase in a tableView - ios

First Off I know this question has been asked but all the solutions I've tried hasn't worked. I want to take data from my firebase real-time database and put it into a tableView. My database is set up like this:
Clubs-
Club1-
Name- Club1
date- 5/09/18
In each tableView cell, I want to see my club name followed by the date. My code compiles fine but dosen't do anything.
My TableViewControllers Title is "Cell" but I don't have a reuse identifier on the tableViewCell.
//
// CoolTable.swift
//
//
// Created by AISD on 4/2/19.
//
import UIKit
import Firebase
import GoogleSignIn
var refa: DatabaseReference!
class CoolTable: UITableViewController{
var posts = [eventStruct]()
#IBOutlet var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
refa = Database.database().reference()
loadNews()
tableview.delegate = self
tableview.dataSource = self
}
struct eventStruct {
let name: String!
let date: String!
}
func loadNews() {
refa.child("Club").queryOrderedByKey().observe(.childAdded, with: { (snapshot) in
if let valueDictionary = snapshot.value as? [AnyHashable:String]
{
let name = valueDictionary["Name"]
let date = valueDictionary["date"]
self.posts.insert(eventStruct(name: name, date: date), at: 0)
self.tableview.reloadData()
}
})
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].name
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].date
return cell
}
}

You should give your cell a reuse identifier of "Cell" since that is what you're trying to get.
numberOfRowsInSection is asking for how many rows your table will have, in your case this should be posts.count.
In numberOfSections try just returning 1.
Finally, create a class for your TableViewCell to properly set the labels values. Simple explanation here.

Related

How to wait for an array to be filled in Swift

I am writing an app in Swift and having problems filling a tableview the right way.
I am getting my data from Firestore and have a class to help me get that data. The basic process is that I have a getProducts function which sets a local array variable with products. The next step is to create an array of objects in my tableview class but my there seems to be a fault where my tableview gets build before my function has the time to load in the array.
So my loadProducts fills the array products but my count seems to be 0.
Hope you guys can help, thank you in advance
My code:
class ProductTableViewController: UITableViewController {
var products = [Product]()
override func viewDidLoad() {
super.viewDidLoad()
loadProducts()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return products.count
}
private func loadProducts(){
let dbhelper = DBHelper()
dbhelper.getProducts(){ success in
self.products = dbhelper.products
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "ProductTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? ProductTableViewCell else {
fatalError("The dequeued cell is not an instance of ProductTableViewCell.")
}
let product = products[indexPath.row]
cell.titleLabel.text = product.Titel
cell.priceLabel.text = product.Prijs
return cell
}
}
Inside you load products func add a table view reload statment in order to reload the table with your new data :
private func loadProducts(){
let dbhelper = DBHelper()
dbhelper.getProducts(){ success in
self.products = dbhelper.products
Self.tableView.reloadData()
}
}

Display Firebase Data in UITableView

I am trying to make a UITableView display data from my firebase database which is in the following structure
I need the first label to display the shop's name and the shop's type. When I print the values from the database, it displays the list of the shops and the type next to it. However, I am finding it difficult to replicate this into the UITableView. Thank you for the help. Here is my code:
import UIKit
import Firebase
struct shopStruct {
let shopName: String!
let shopType : String!
}
class HomeViewController: UIViewController, UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var homeTableView: UITableView!
var databaseRef: DatabaseReference!
var shops = [shopStruct]()
override func viewDidLoad() {
super.viewDidLoad()
databaseRef = Database.database().reference()
databaseRef.child("shops").queryOrderedByKey().observe(.childAdded, with: { (snapshot) in
if let valueDictionary = snapshot.value as? [AnyHashable:String]
{
let shopName = valueDictionary["name"]
let shopType = valueDictionary["type"]
self.shops.insert(shopStruct(shopName: shopName, shopType: shopType), at: 0)
self.homeTableView.reloadData()
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return shops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = shops[indexPath.row].shopName
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = shops[indexPath.row].shopType
return cell
}
}
You have to set in viewDidLoad
self.homeTableView.dataSource = self
May be it's not working because you'r reloading the tablebview on secondary thread so could you please replace the code self.homeTableView.reloadData() with following code and try?
DispatchQueue.main.async {
self.homeTableView.reloadData()
}

empty tableview cell for at index path row is not called

All the tableview functions are working except cell for row index path .
The problem maybe that foods array is empty so the number for rows is 0 so the cell for row at index path is not called
#IBOutlet weak var foooods: UITableView!
var databaseref = Database.database().reference()
var img : AnyObject?
var foods = [String?]()
override func viewDidLoad() {
super.viewDidLoad()
self.databaseref.child("basic food").observe(.childAdded, with: {( snap: DataSnapshot) in
let snapp = snap.value as! [String:AnyObject]
if let x = snapp["name"] as! String? {
self.foods.insert(x, at: 0)
//self.foods.append(x)
}
})
self.foooods.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.foods.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("difufuehf")
let cell : foodsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "aupa", for:indexPath) as! foodsTableViewCell
print("fufvksdfvysdgfvjdsgfdsygfvds,jhvjsdvsdjvguydsfgdsylfgdsyfgsdlygfsiygf")
if let foo = foods[indexPath.row] {
print(foo)
cell.food.text = foo
}
return cell
}
This must be a duplicate but I can't find one.
Your issue is that you call reloadData in the wrong place which results in it being called far too soon. You need to call it inside the completion block, after you update your data model.
And you need to make sure it gets called on the main queue.
override func viewDidLoad() {
super.viewDidLoad()
self.databaseref.child("basic food").observe(.childAdded, with: {( snap: DataSnapshot) in
if let snapp = snap.value as? [String:Any], let x = snapp["name"] as? String {
self.foods.insert(x, at: 0)
//self.foods.append(x)
DispatchQueue.main.async {
self.foooods.reloadData()
}
}
})
}
Note that I also fixed the way the value is obtained. You really need to avoid force unwrapping and force casting.

How to display firebase information in my iOS swift listview controller?

I am having difficulty getting firebase into my controller. Firebase is working correctly due to me being able to out print to the console. I need to be able to display all data in my app. Please assist!
//
// All.swift
// Guaranteed Pricing
//
import Foundation
import UIKit
import Firebase
class All: UINavigationController, UITableViewDataSource, UITableViewDelegate {
var items: [String] = []
var tableView: UITableView!
let cellIdentifier = "CellIdentifier"
override func viewDidLoad(){
super.viewDidLoad()
self.tableView = UITableView(frame:self.view!.frame)
self.tableView!.delegate = self
self.tableView!.dataSource = self
self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
self.view?.addSubview(self.tableView)
let ref = Firebase(url:"https://sizzling-inferno-451.firebaseio.com/services")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
for child in snapshot.children {
// let key = child.key //returns -Jikaijsipaij and -kalksdokoas
// let name = child.value.objectForKey("service_name") as NSString?
////
// self.items.append(key)
}
// do some stuff once
print(snapshot.value)
// get these values and put them in the cell's text view. key is more important
print(snapshot.key)
// add to the array and just this array
self.tableView!.reloadData()
})
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)
// Fetch Fruit
let fruit = items[indexPath.row]
// Configure Cell
cell.textLabel?.text = fruit
return cell
}
// onclick printing
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(items[indexPath.row])
}
}
Here's a quick snippet to populate an array within a block, and then once populated reload the tableview to display the data.
user_id_0
name: "Fred"
friend: "Barney"
And the code to read in all of the users, iterate over them and extract each name and add it to an array:
var namesArray: [String] = []
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
for child in snapshot.children {
let name = child.value["name"] as! String
namesArray.append(name)
}
self.myTableView.reloadData()
})

iOS Swift: Getting repeated value while updating 2D Array in custom UITableView cell

I have a 2D Array which I want to populate in UITableView Custom Cell in a specific pattern.
//Retrieved from Parse backend
var myArray = [["Name1", "Age1"],["Name2", "Age2"],["Name3", "Age3"]]
//What I need is:
nameArray = ["Name1", "Name2", "Name3"]
ageArray = ["Age1", "Age2", "Age3]
So that I can use indexPath to fill the Name data in the custom UITableView cell For Ex: nameArray[indexPath.row]
I tried using the for in loop,
var nameArray = NSMutableArray()
var ageArray = NSMutableArray()
//Inside CellForRowAtIndexPath
for data in myArray {
self.nameArray.addObject(data[0])
self.ageArray.addObject(data[1])
}
cell.nameLabel.text = "\(nameArray[indexPath.row])"
cell.ageLabel.text = "\(ageArray[indexPath.row])"
But I am getting repetitive name and age label filled with Name1 and Age1 in both the cell. Does anyone know whats wrong in this?
Is there a better way to reload this data as needed?
// UPDATED FULL WORKING CODE Thanks to #l00phole who helped me solve the problem
class NewViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var data = [[String]]()
var cost = Double()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
uploadData()
}
func uploadData() {
let query = PFQuery(className:"Booking")
query.getObjectInBackgroundWithId("X0aRnKMAM2") {
(orders: PFObject?, error: NSError?) -> Void in
if error == nil && orders != nil {
self.data = (orders?.objectForKey("orderDetails"))! as! [[String]]
//[["Vicky","21"],["Luke", "18"],["7253.58"]]
//*****Removing the last element as it is not needed in the tableView data
let count = self.data.count - 1
let c = self.data.removeAtIndex(count)
cost = Double(c[0])!
//******
} else {
print(error)
}
self.reloadTableData()
}
}
func reloadTableData()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:NewTableViewCell = self.tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! NewTableViewCell
// Configure the cell...
cell.nameLabel.text = "\(data[indexPath.row][0])"
cell.ageLabel.text = "\(data[indexPath.row][1])"
return cell
}
You are adding to the nameArray and ageArray every time cellForRowAtIndexPath is called and you are not clearing them first. This seems inefficient and you should only populate those arrays when the input data changes, not when generating the cells.
I don't even think you need those arrays, as you could just do:
cell.nameLabel.text = "\(data[indexPath.row][0])"
cell.ageLabel.text = "\(data[indexPath.row][1])"
You don't have to create separate array for name and age, you can use the existing myArray as below
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:NewTableViewCell = self.tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! NewTableViewCell
// Configure the cell...
let dataArray = myArray[indexPath.row]
cell.nameLabel.text = "\(dataArray[0])"
cell.ageLabel.text = "\(dataArray[1])"
return cell
}
}

Resources