Display Firebase Data in UITableView - ios

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()
}

Related

How to utilize a custom tableview cell nib in iOS with a swipe table view controller as the cell's default controller

I am a beginner and I'm having some issues with an iOS app I'm creating. I am utilizing the SwipeCellKit package to have swipeable cells for my tableViews. I would also like to use a custom cell to display birthdays. I created a custom tableView cell and nib. The issue that I'm running into is properly coding the nib into my birthday tableView controller so it will display the information. Below is a picture of my code. I'd really appreciate if someone could point me in the right direction.
import UIKit
import RealmSwift
import UserNotifications
class BirthdayTableViewController: SwipeTableViewController {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var birthdayLabel: UILabel!
#IBOutlet weak var age: UILabel!
let realm = try! Realm()
var birthdays: Results<Birthday>?
let dateFormatter = DateFormatter()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(BirthdayTableViewCell.nib(), forCellReuseIdentifier: BirthdayTableViewCell.identifier)
tableView.rowHeight = 100
tableView.separatorStyle = .none
}
override func viewWillAppear(_ animated: Bool) {
loadBirthdays()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return birthdays?.count ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
guard let birthdayCell = (tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! BirthdayTableViewCell) else {fatalError()}
let birthday = birthdays?[indexPath.row]
let firstName = birthday?.firstName ?? ""
let lastName = birthday?.lastName ?? ""
name?.text = firstName + " " + lastName
if let date = birthday?.birthdate as Date? {
birthdayLabel?.text = dateFormatter.string(from: date)
} else {
birthdayLabel.text = " "
}
return cell
}
[Beginning of Code][1]
[TableView Methods][2]
[1]: https://i.stack.imgur.com/fZspG.png
[2]: https://i.stack.imgur.com/9IlD1.png
The app crashes due to casting a result of
tableView.dequeueReusableCell(withIdentifier:for:)
with force unwrap as! which returns non optional object.
To solve the error, just change it to as?
There is another thing which can lead to an error as well, you typed direct identifier of a cell instead using the identifier BirthdayTableViewCell.identifier
guard let birthdayCell = (tableView.dequeueReusableCell(withIdentifier: BirthdayTableViewCell.identifier, for: indexPath) as? BirthdayTableViewCell) else {fatalError()}

I want to display data from firebase in a tableView

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.

Error while trying to download Image URL from Firebase database using Swift3

Would you please help me to find the error in my code? I have an image URL in my database and I'm trying to download it and display it in a TableView, but it shows nil value.
This is my Class:
class Post : NSObject {
var Posts : String!
var Image : String!
}
and this is My TableView.
import UIKit
import FirebaseDatabase
import SDWebImage
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var MyImageView: UIImageView!
#IBOutlet weak var tableView: UITableView!
var Ref:FIRDatabaseReference?
var Handle:FIRDatabaseHandle?
var myarray = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
Ref=FIRDatabase.database().reference()
Handle = Ref?.child("Posts").observe(.childAdded ,with: { (snapshot) in
let post = snapshot.value as? Post
self.myarray.append(post!)
self.tableView.reloadData()
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return myarray.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as? TableViewCell {
// cell?.textLabel?.text = PostData[indexPath.row]
let url = URL(string : self.myarray [(indexPath as NSIndexPath).row].Image!)
cell.MyImage.sd_setImage(with: url)
return cell
}else{
let cell = TableViewCell()
let url = URL(string : self.myarray [(indexPath as NSIndexPath).row].Image!)
cell.MyImage.sd_setImage(with: url)
return cell
}
}
}

Gets number of rows but doesn't print

I have a program written in Swift 3, that grabs JSON from a REST api and appends it to a table view.
Right now, I'm having troubles with getting it to print in my Tableview, but it does however understand my count function.
So, I guess my data is here, but it just doesn't return them correctly:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, HomeModelProtocal {
#IBOutlet weak var listTableView: UITableView!
func itemsDownloaded(items: NSArray) {
feedItems = items
self.listTableView.reloadData()
}
var feedItems: NSArray = NSArray()
var selectedLocation : Parsexml = Parsexml()
override func viewDidLoad() {
super.viewDidLoad()
self.listTableView.delegate = self
self.listTableView.dataSource = self
let homeModel = HomeModel()
homeModel.delegate = self
homeModel.downloadItems()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "BasicCell"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: Parsexml = feedItems[indexPath.row] as! Parsexml
myCell.textLabel!.text = item.title
return myCell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedItems.count
}
override func viewDidAppear(_ animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Are you by any chance able to see the error that I can't see?
Note. I have not added any textlabel to the tablerow, but I guess that there shouldn't be added one, when its custom?
Try this code:
override func viewDidLoad() {
super.viewDidLoad()
print(yourArrayName.count) // in your case it should be like this print(feedItems.count)
}

Populate the data saved on core data on a tableView

The code of my first UIViewController looks like this and basically I want to save the data whatever I type on the UITextField and retrieve it and populate on a UITableView. code as below. (I think my issue is in the cellForRow method)
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet weak var textField1: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func nxtbuttonpressed(_ sender: AnyObject) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
//Lets save data
let newUser = NSEntityDescription.insertNewObject(forEntityName: "Expenses", into: context)
newUser.setValue(textField1.text, forKey: "expenseName")
do {
try context.save ()
print("data saved successfully")
}catch{
print("There was an error")
}
performSegue(withIdentifier: "ShowNxtVC", sender: nil)
}
}
This is where I retrieve the data that I saved in the above VC (as the code bellow). However even though I can print all the data on the console, only the last data item I saved will populate to the UITableViewCell. How can i overcome this as to populate all the data that I've saved before instead the one that i saved last.
import UIKit
import CoreData
class TableViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var myArray : Array? = []
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest <NSFetchRequestResult> (entityName: "Expenses")
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
// check data existance
if results.count>0 {
print(results.count)
for resultGot in results as! [NSManagedObject]{
if let expName = resultGot.value(forKey:"expenseName") as? String{
myArray = [expName]
print("my array is : \(myArray)")
}
}
}
}catch{
print("No Data to load")
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(myArray?.count)
return myArray!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell ()
cell.textLabel?.text = myArray? [indexPath.row] as! String?
return cell
}
}
first off all you have to change this:
myArray = [newValue] because that resets your array with just one value every time it finds a new expense in core data.
var array = [String]()
array = ["hello"]
array = ["joe"]
print(array)
// returns: ["joe"]
use:
myArray.append(newExpense)
and you get:
var array2 = [String]()
array2.append("hello")
array2.append("joe")
print(array2)
// returns: ["hello", "joe"]
After the FOR loop you add:
tableView.reloadData()
Now you should be up and running
There is another thing you should do:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpCell", for: indexPath)
cell.textLabel?.text = myArray?[indexPath.row] as! String
return cell
}
In your Storyboard you need to put ExpCell as reuse identifier into the TableViewCell. The dequeReusableCell command loads only the cells you can see on your device and reuses those cells after you scrolled them out of sight. This way your app uses much less memory and will be faster.
update table view with data, after myArray = [expName] use
DispatchQueue.main.async { [unowned self] in
self.tableView.reloadData()
}
change the tableview cell for row at index path function that will solve your problem
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier identifier: String,
for indexPath: IndexPath)
if(!cell){
cell = tableView.register(tableViewCellClass,forCellReuseIdentifier identifier: String)
}
return cell
}

Resources