how to reload tableview automatically - ios

Hi I am doing a post screen where users add post and view them.This is the viewcontroller for viewing. I am getting information from firebase and reload that info to my table view cells everything is going perfect. However to reload the screen and see if my posts are up to date I need to close the application and run it again each time although I use .reloadData() function and it doesn't reload automatically after each posting. here is my code where do I do the mistake? or am I missing something?
override func viewDidLoad() {
super.viewDidLoad()
self.navcik.title = "Posts"
tableView = UITableView(frame:view.bounds, style: .plain)
view.addSubview(tableView)
let cellnib = UINib(nibName: "postTableCell", bundle: nil)
tableView.register(cellnib, forCellReuseIdentifier: "postCell")
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
observeposts()
}
func observeposts() {
let db = Firestore.firestore()
db.collection("posts").getDocuments { (snap, error) in
var tempposts = [Post]()
if error != nil {
print("error:\(String(describing: error))")
} else {
for document in snap!.documents {
if let dict = document.data() as? [String: Any] ,
let username = dict["username"] as? String,
let title = dict["title"] as? String,
let desc = dict["desc"] as? String {
let post = Post(id: "1", username: username, title: title, desc: desc)
tempposts.append(post)
}
}
self.posts = tempposts
self.tableView.reloadData()
}
}
}
#IBOutlet weak var navcik: UINavigationItem!
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! postTableCell
cell.set(post: posts[indexPath.row])
return cell
}

Well I just added a refresher and observed the posts there and reloaded, works perfect now.

try this
for document in snap!.documents {
if let dict = document.data() as? [String: Any] ,
let username = dict["username"] as? String,
let title = dict["title"] as? String,
let desc = dict["desc"] as? String {
let post = Post(id: "1", username: username, title: title, desc: desc)
tempposts.append(post)
}
tableView.reloadData()
}

Related

Index out of range error keeps crashing my app

I have a tableview loading data from firebase database. When i open my app the data does not populate. it crashes and throws the error index out of range. I am fairly new to xcode and would appreciate the help. i have been given recommendations on how to fix my code with regards to having multiple arrays but everyone that advices forget i'm new and does realize that i am pulling imageurls into my tableview too and dont know how to adopt their recommendations into my code. if i could get help getting passed this error that would be awesome.
import UIKit
import FirebaseAuth
import FirebaseDatabase
class EventsViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var eventsRef: DatabaseReference?
var eventsDatabaseHandle:DatabaseHandle?
var eventsTitles = [String]()
var eventTimestamps = [String]()
var eventsLocations = [String]()
var eventsImages = [UIImage]()
#IBOutlet weak var addEventsButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
adminAuth()
eventsRef = Database.database().reference()
tableView.reloadData()
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
tableView.delegate = self
tableView.dataSource = self
eventsDatabaseHandle = eventsRef?.child("Church Events").observe(.childAdded, with: { (snaphot) in
let eventPost = snaphot.value as! [String: Any]
self.eventTimestamps.append(eventPost["eventdate"] as! String)
self.eventsTitles.append(eventPost["eventtitle"] as! String)
self.eventsLocations.append(eventPost["eventlocation"] as! String)
let task = URLSession.shared.dataTask(with: URL(string: eventPost["ImageUrl"] as! String)!) {(data, response, error) in
if let image: UIImage = UIImage(data: data!) {
self.eventsImages.append(image)
}
}
task.resume()
self.tableView.reloadData()
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return eventsTitles.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "events") as! EventsTableViewCell
// let image = eventsImages[indexPath.row]
cell.flyerImages.image? = eventsImages[indexPath.row] **<- index out of range**
cell.eventTitle.text! = eventsTitles[indexPath.row]
cell.eventDate.text! = eventTimestamps[indexPath.row]
cell.eventLocation.text! = eventsLocations[indexPath.row]
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
return cell
}
func adminAuth() {
if (Auth.auth().currentUser!.displayName != "Neil Leon") {
self.addEventsButton.tintColor = UIColor.clear
self.addEventsButton.isEnabled = false
}
else{
self.addEventsButton.isEnabled = true
}
}
}``````
At the moment reloadData is called the image array is empty and causes the crash
Use a custom struct and reload the table view after the image data has been received
struct Event {
let title, timestamp, location : String
var image : UIImage?
}
var events = [Event]()
...
eventsDatabaseHandle = eventsRef?.child("Church Events").observe(.childAdded, with: { (snaphot) in
let eventPost = snaphot.value as! [String: Any]
let event = Event(title: eventPost["eventtitle"] as! String,
timestamp: eventPost["eventdate"] as! String,
location: eventPost["eventlocation"] as! String,
image: nil)
let task = URLSession.shared.dataTask(with: URL(string: eventPost["ImageUrl"] as! String)!) { data, _, error in
if let error = error {
print(error)
} else {
event.image = UIImage(data: data!)
DispatchQueue.main.async {
self.events.append(event)
self.tableView.reloadData()
}
}
}
task.resume()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return events.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "events", for: indexPath) as! EventsTableViewCell
let event = events[indexPath.row]
cell.flyerImages.image = event.image
cell.eventTitle.text = event.title
cell.eventDate.text = event.timestamp
cell.eventLocation.text = event.location
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
return cell
}

My data from firebase database is not loading into my tableview

I have a tableview loading data from firebase database. When I open my app the data does not populate. when I create a new post I can see the tableview cells modifying like changed were made but the post doesn't populate. I can't figure it out.
import UIKit
import FirebaseAuth
import FirebaseDatabase
class EventsViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var eventsRef: DatabaseReference?
var eventsDatabaseHandle:DatabaseHandle?
var eventsTitles = [String]()
var eventTimestamps = [String]()
var eventsLocations = [String]()
var eventsImages = [UIImage]()
#IBOutlet weak var addEventsButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
adminAuth()
eventsRef = Database.database().reference()
tableView.reloadData()
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
tableView.delegate = self
tableView.dataSource = self
eventsDatabaseHandle = eventsRef?.child("Church Events").observe(.childAdded, with: { (snaphot) in
let eventPost = snaphot.value as! [String: Any]
self.eventTimestamps.append(eventPost["eventdate"] as! String)
self.eventsTitles.append(eventPost["eventtitle"] as! String)
self.eventsLocations.append(eventPost["eventlocation"] as! String)
let task = URLSession.shared.dataTask(with: URL(string: eventPost["ImageUrl"] as! String)!) {(data, response, error) in
if let image: UIImage = UIImage(data: data!) {
self.eventsImages.append(image)
}
}
self.tableView.reloadData()
task.resume()
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return eventsImages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "events") as! EventsTableViewCell
let image = eventsImages[indexPath.row]
cell.flyerImages.image! = image
cell.eventTitle.text! = eventsTitles[indexPath.row]
cell.eventDate.text! = eventTimestamps[indexPath.row]
cell.eventLocation.text! = eventsLocations[indexPath.row]
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
tableView.reloadData()
return cell
}
func adminAuth() {
if (Auth.auth().currentUser!.displayName != "Neil Leon") {
self.addEventsButton.tintColor = UIColor.clear
self.addEventsButton.isEnabled = false
}
else{
self.addEventsButton.isEnabled = true
}
}
}
image of empty tableview
]
So the code below is not tested as I don't have firebase setup currently.
However, observing childAdded... the documentation says it will pass all of the current records in the database at first and will then just post new additions. So all you need to do is loop through them, setup your tableView data source and reload the table.
Rather than use multiple arrays for values I've created an array of ChurchEvent objects instead.
struct ChurchEvents {
let title: String
let location: String?
let date: Date?
let imageUrlString: String?
init(dict: [String: Any]) {
self.title = dict["title"] as String
self.location = dict["location"] as? String
// etc
}
}
var events = [ChurchEvents]()
eventsDatabaseHandle = eventsRef?.child("Church Events").observe(.childAdded, with: { snapshot in
let list = snapshot.value as? [[String : AnyObject]]
let newEvents = list.map { ChurchEvent(dict: $0) }
events.append(newEvents)
tableView.reloadData()
}
Other improvements you could make:
class EventsTableViewCell: UICollectionViewCell {
func configure(with event: ChurchEvent {
eventDate.text = event.date
eventTitle.text = event.title
eventLocation.text = event.location
// etc
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "events") as! EventsTableViewCell
let event = events[indexPath.row]
cell.configure(with: event)
return cell
}

Firestore into TableView [Swift]

I've already seen: Swift UITableView reloadData in a closure but it still does not work. That's why I'm creating a new thread for this.
I'm trying to insert Firestore data into a custom tableview. But when I print the numbers it returns (In the console):
"MyDogwalk.listTxt"
And no data is showing up on the tableview.
I guess all of this is relevant. (I also have 2 classes, with init etc)
class HistoryViewController: UIViewController {
//Tableview
#IBOutlet weak var tableView: UITableView!
let db = Firestore.firestore()
var list: [listTxt] = []
override func viewDidLoad()
{
super.viewDidLoad()
list = createArray()
tableView.delegate = self
tableView.dataSource = self
}
func createArray() -> [listTxt]
{
var tempTxt: [listTxt] = []
//Authentication
let authentication = Auth.auth().currentUser?.uid
//Choosing collection
db.collection("rastad").document(authentication!).collection("promenad").getDocuments()
{ (QuerySnapshot, err) in
if err != nil
{
print("Error getting documents: \(String(describing: err))");
}
else
{
//For-loop
for _ in QuerySnapshot!.documents
{
self.list.removeAll()
let document = QuerySnapshot!.documents.first
let data = document!.data()
data.forEach { (item) in
let data1 = data["Dog"] as? String
let data2 = data["Person"] as? String
let data3 = data["What"] as? String
let data4 = data["Date"] as? String
let data5 = data["Time"] as? String
let txt = listTxt(dog: data1!, person: data2!, action: data3!, time: data4!, date: data5!)
print(txt)
tempTxt.append(txt)
}
}
self.tableView.reloadData()
}
}
//return tempTxt
return list
}
}
extension HistoryViewController: UITableViewDelegate, UITableViewDataSource
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let listPath = list[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! HistoryCell
cell.setCell(list: listPath)
return cell
}
}
And.. Why is this downvoted? I got an answer that was actually working for this case, and the question is detailed enough for people to understand, isn't it?
createArray() method runs async code, and fills tempTxt. But you are returning tempTxt before async code has been run. So instead returning from createArray method and setting its value to self.list, just do it in the method itself:
self.list = tempTxt
self.tableView.reloadData()
You are iterating over documents but always using data of documents.first. Try this:
self.list.removeAll()
for document in QuerySnapshot!.documents {
let data = document!.data()
data.forEach { (item) in
let data1 = data["Dog"] as? String
let data2 = data["Person"] as? String
let data3 = data["What"] as? String
let data4 = data["Date"] as? String
let data5 = data["Time"] as? String
self.list.append(listTxt(dog: data1!, person: data2!, action: data3!, time: data4!, date: data5!))
}
}
self.tableView.reloadData()
Change self.tableView.reloadData() to
self.list = tempTxt
DispatchQueue.main.async {
self.tableView.reloadData()
}
And skip returning array from that func

Firebase to Tableview issue

I am having issues getting my data from firebase to show on my TableView. I only want the vin number to display on the table view. Right now i am either getting cells that display "nil", or nothing in the cells.
My goal is to have each cell display the Vin Number.
Can someone take a look and let me know where i have an issue?
Thanks!!!
Alex
here is what my firebase database looks like
child --Vehicles
child--5UXKR0C34H0X82785
child-- VehicleInfo
then under the "vehicle Info" child it displays these three fields
make:"toyota"
model:"corolla"
VinNumber: "5UXKR0C34H0X82785"
Here is my Vehicle model class
import Foundation
import FirebaseDatabase
struct VehicleModel {
var Make: String?
var Model: String?
var VinNumber: String?
init(Make: String?, Model: String?, VinNumber: String?){
self.Make = Make
self.Model = Model
self.VinNumber = VinNumber
}
init(snapshot: DataSnapshot) {
let snapshotValue = snapshot.value as! [String: AnyObject]
VinNumber = snapshotValue["VinNumber"] as? String
Make = snapshotValue["Make"] as? String
Model = snapshotValue["Model"] as? String
}
}
Here is my view controller code
import UIKit
import Firebase
import FirebaseDatabase
class InventoryTableViewController: UITableViewController{
var ref: DatabaseReference!
var refHandle: UInt!
var userList = [VehicleModel]()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
tableView.delegate = self
tableView.dataSource = self
tableView?.register(UITableViewCell.self, forCellReuseIdentifier:
"cellId")
fetchUsers()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return userList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
// Set cell contents
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for:
indexPath) as UITableViewCell
let eachvehicle = userList[indexPath.row]
cell.textLabel!.text = "\(String(describing: eachvehicle.VinNumber))"
return cell
}
func fetchUsers(){
refHandle = ref.child("Vehicles").observe(.childAdded, with: {
(snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
print(dictionary)
let VinNumber = dictionary["VinNumber"]
let Make = dictionary["Make"]
let Model = dictionary["Model"]
self.userList.insert(VehicleModel(Make: Make as? String, Model:
Model as? String, VinNumber: VinNumber as? String), at: 0)
self.tableView.reloadData()
}
})
}
}
Also, I am having issues displaying the make and model of the selected cell in another view controller connected by a segue. I have attempted to set up passing the values but can not get it to work.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let destination = storyboard.instantiateViewController(withIdentifier:
"AdditionalInfoViewController") as! AdditionalInfoViewController
navigationController?.pushViewController(destination, animated: true)
performSegue(withIdentifier: "toAdditionalInfo", sender: self)
let row = indexPath.row
print("working so far ")
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
makeToPass = currentCell.Model
modelToPass = currentCell.Make
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMapView" {
var viewController = segue.destination as! AdditionalInfoViewController
viewController.makeToPass = makeValueToPass
viewController.modelToPass = modelValueToPass
}
}
Correct me if I'm wrong, but this is your data structure, right?
Vehicles: {
5UXKR0C34H0X82785: {
VehicleInfo: {
make:"toyota",
model:"corolla",
VinNumber: "5UXKR0C34H0X82785"
}
}
}
Which means in order to access the data under VehicleInfo, you need to specify that location. There are a few ways you can do this, but one of them would be using childSnapshot(forPath:)
func fetchUsers(){
refHandle = ref.child("Vehicles").observe(.childAdded, with: {
(snapshot) in
if let dictionary = snapshot.childSnapshot(forPath: "VehicleInfo").value as? [String: AnyObject] {
print(dictionary)
let VinNumber = dictionary["VinNumber"]
let Make = dictionary["Make"]
let Model = dictionary["Model"]
self.userList.insert(VehicleModel(Make: Make as? String, Model:
Model as? String, VinNumber: VinNumber as? String), at: 0)
self.tableView.reloadData()
}
})
}
}

Fetch data from Firebase Database to tableview

First I get these values into my Firebase Database, which works successfully.
func handleSale() {
let ref = FIRDatabase.database().reference().child("tickets")
let childRef = ref.childByAutoId()
guard let Price = emailTextField.text, ticketName = passwordTextField.text else {
print("Form is not valid")
return
}
let values: [String: AnyObject] = ["Price": Price, "ticketName": ticketName]
ref.observeEventType(.ChildAdded, withBlock: { (snapshot) in
let ticketId = snapshot.key
let ticksRef = FIRDatabase.database().reference().child("tickets").child(ticketId)
ticksRef.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else {
return
}
self.messages.append(Ticket(dictionary: dictionary))
childRef.updateChildValues(values) { (error, ref) in
if error != nil {
print(error)
return
}
print(snapshot)
print(dictionary)
print(ticketId)
}
}, withCancelBlock: nil)
})
}
I then tried to setup a tableview with a custom cell class and fetch these values into the tableview, however being fairly new to swift, I know I haven't done this correctly. In the end I would like that my values "price" and "ticketName" shows up in my table's..
here is my tableview:
import UIKit
import Firebase
class Sales: UITableViewController {
let cellId = "cellId"
var messages = [Ticket]()
var messagesDictionary = [String: Ticket]()
override func viewDidLoad() {
super.viewDidLoad()
var messages = [Ticket]()
var messagesDictionary = [String: Ticket]()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .Plain, target: self, action: #selector(heya))
tableView.registerClass(FredericCell.self, forCellReuseIdentifier: cellId)
func fetchTicket() {
FIRDatabase.database().reference().child("tickets").observeEventType(.ChildAdded, withBlock: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let ticketId = snapshot.key
Ticket.setValuesForKeysWithDictionary(dictionary)
return
}
}, withCancelBlock: nil)
}
print("test to see if it works")
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as! FredericCell
return cell
}
func heya() {
print ("working")
}
I have edited in hope of filling out my cells, but without luck..:
override func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return tickets
.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as! FredericCell
let ticket = tickets[indexPath.row]
cell.textLabel?.text = ticket.ticketName
cell.detailTextLabel?.text = ticket.Price
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
return cell
}

Resources