Trying to fetch data from a firebase database and display the results in a view table

I am creating an application where users can set reminders for things. The application is connected to a firebase database where all of the data is stored. When the user saves the the event that they are setting this new even should appear on the home page in a table view. I keep getting the error:

"Extra trailing closure passed in call"

I have been unable to find a solution that fixes the function so I am able to view the data. Here is my code below

import FirebaseAuth
import Firebase
import FirebaseDatabase
import FirebaseFirestore

class DashboardViewController: UIViewController {

  @IBOutlet weak var reminderList: UITableView!
  var reminders = [EntryViewController]()
  
func viewWillAppear(animated: Bool) {
  viewWillAppear(animated: animated)
    loadData()
  }
   
    func loadData() {
    self.reminders.removeAll()
    let ref = Database.database().reference()
    ref.child("usersEvents").observeSingleEvent(of: .value, withBlock: { (snapshot) in
      if let reminderDict = snapshot.value as? [String:AnyObject] {
        for (_,reminderElement) in reminderDict {
          print(reminderElement);
          let reminder = Reminder()
          reminders.event = reminderElement["event"] as? String
          reminders.dateAndTime = reminderElement["data and time"] as? String
          reminders.message = reminderElement["notes"] as? String
          self.reminders.append(reminder)
        }
      }
       
   
      self.tableView.reloadData()
       
    }) { (error) in
        print(error.localizedDescription)
     }
  }
   
  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.reminders.count
  }

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell")
    cell!.textLabel?.text = reminders[indexPath.row].event
    return cell!
  }
   
}

I am getting the error on this line

  }) { (error) in
Answered by Claude31 in 711220022

I do not practice Firebase, but looked at doc: https://firebase.google.com/docs/reference/swift/firebasedatabase/api/reference/Classes/DatabaseQuery#observesingleeventof:with:withcancel:

The API is

func observeSingleEvent(of eventType: DataEventType, with block: @escaping (DataSnapshot) -> Void, withCancel cancelBlock: ((Error) -> Void)? = nil)

So most likely your code should be:

          ref.child("usersEvents").observeSingleEvent(of .value, with: { (snapshot) in
               if let reminderDict = snapshot.value as? [String:AnyObject] {
                    for (_,reminderElement) in reminderDict {
                         print(reminderElement);
                         let reminder = Reminder()
                         reminders.event = reminderElement["event"] as? String
                         reminders.dateAndTime = reminderElement["data and time"] as? String
                         reminders.message = reminderElement["notes"] as? String
                         self.reminders.append(reminder)
                    }
               }
               self.tableView.reloadData()  // Should it be inside the if let ?
               
          }, withCancel: { (error) in
               print(error.localizedDescription)
          })

.

What do you want to do in viewWillAppear ? You call it recursively, in an infinite loop (but in fact it will never be called, because the system will not recognise the signature) and it will not compile as is.

func viewWillAppear(animated: Bool) {  // define a new func ? In fact, need to override
  viewWillAppear(animated: animated) // recursive call
    loadData()
  }

You probably want:

     override func viewWillAppear(_ animated: Bool) {

          super.viewWillAppear(animated)
          loadData()
     }

It seems you are using very old API versions. Take care.

This

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

is now:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

And calling cell!.textLabel is now deprecated. You should replace with ContentConfiguration.

In addition, forcing unwrap is dangerous, better use if let

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell") {
        var content = cell.defaultContentConfiguration()
        content.text = reminders[indexPath.row].event
        cell.contentConfiguration = content
        return cell
     } else {
         return UITableViewCell()
     }
}
Accepted Answer

I do not practice Firebase, but looked at doc: https://firebase.google.com/docs/reference/swift/firebasedatabase/api/reference/Classes/DatabaseQuery#observesingleeventof:with:withcancel:

The API is

func observeSingleEvent(of eventType: DataEventType, with block: @escaping (DataSnapshot) -> Void, withCancel cancelBlock: ((Error) -> Void)? = nil)

So most likely your code should be:

          ref.child("usersEvents").observeSingleEvent(of .value, with: { (snapshot) in
               if let reminderDict = snapshot.value as? [String:AnyObject] {
                    for (_,reminderElement) in reminderDict {
                         print(reminderElement);
                         let reminder = Reminder()
                         reminders.event = reminderElement["event"] as? String
                         reminders.dateAndTime = reminderElement["data and time"] as? String
                         reminders.message = reminderElement["notes"] as? String
                         self.reminders.append(reminder)
                    }
               }
               self.tableView.reloadData()  // Should it be inside the if let ?
               
          }, withCancel: { (error) in
               print(error.localizedDescription)
          })

.

What do you want to do in viewWillAppear ? You call it recursively, in an infinite loop (but in fact it will never be called, because the system will not recognise the signature) and it will not compile as is.

func viewWillAppear(animated: Bool) {  // define a new func ? In fact, need to override
  viewWillAppear(animated: animated) // recursive call
    loadData()
  }

You probably want:

     override func viewWillAppear(_ animated: Bool) {

          super.viewWillAppear(animated)
          loadData()
     }

It seems you are using very old API versions. Take care.

This

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

is now:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

And calling cell!.textLabel is now deprecated. You should replace with ContentConfiguration.

In addition, forcing unwrap is dangerous, better use if let

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell") {
        var content = cell.defaultContentConfiguration()
        content.text = reminders[indexPath.row].event
        cell.contentConfiguration = content
        return cell
     } else {
         return UITableViewCell()
     }
}

When I made the adjustments to the code I keep getting one error

Cannot find 'of' in scope

I keep getting this error here.

ref.child("usersEvents").observeSingleEvent(of .value, with: { (snapshot) in

This is the new code with the adjustments made I have made every change I can think of but just cant get it to go away

import UIKit
import FirebaseAuth
import Firebase
import FirebaseDatabase
import FirebaseFirestore


class DashboardViewController: UIViewController {

  @IBOutlet weak var reminderList: UITableView!
  var reminders = [EntryViewController]()
  
  override func viewWillAppear(_ animated: Bool) {

     super.viewWillAppear(animated)
     loadData()
  }
   

func loadData() {
  self.reminders.removeAll()
  let ref = Database.database().reference()
  ref.child("usersEvents").observeSingleEvent(of .value, with: { (snapshot) in
    if let reminderDict = snapshot.value as? [String:AnyObject] {
      for (_,reminderElement) in reminderDict {
        print(reminderElement);
        let reminder = Reminder()
        reminders.event = reminderElement["event"] as? String
        reminders.dateAndTime = reminderElement["data and time"] as? String
        reminders.message = reminderElement["notes"] as? String
        self.reminders.append(reminder)
         
      }
       
    }
    self.tableView.reloadData() // Should it be inside the if let ?
          
  }, withCancel: { (error) in
    print(error.localizedDescription)
     
  })
   

   
   
  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.reminders.count
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell") {
      var content = cell.defaultContentConfiguration()
      content.text = reminders[indexPath.row].event
      cell.contentConfiguration = content
      return cell
     } else {
       return UITableViewCell()
     }
  }
   
}
   
}

Of course, forgot colon after of when pasting in editor:

ref.child("usersEvents").observeSingleEvent(of: .value, with: { (snapshot) in

Please format the code, it will be much easier to read.

I then get error `Value of type '[EntryViewController]' has no member 'dateAndTime' Alongside this code 

I think it has something to do with this line but Im not sure let reminder = Reminder()

let reminder = Reminder()  
reminders.event = reminderElement["event"] as? String    
reminders.dateAndTime = reminderElement["data and time"] as? String          
reminders.message = reminderElement["notes"] as? String          
self.reminders.append(reminder)

Hard to say as you do not provide enough information.

  • How is EntryViewController defined ?
  • you declare reminder but never use it, just use reminders
  • reminders is an array of EntryViewController

-> So most likely, you want to call reminders[someIndex].dateAndTime or more probably reminder.dateAndTime

  • idem with reminders.message

Please clarify.

Trying to fetch data from a firebase database and display the results in a view table
 
 
Q