Problem with fetching data from a firebase database and displaying it in a table view

I am currently trying to develop an application that fetches users data from a firebase database and displays it in a table view. The function that I am having problems with is the function that loads the data.

class EntryViewController: NSObject {
   
  var event :String?
  var dateAndTime: String?
  var message: String?
  // id which is set from firebase to uniquely identify it
  var uniqueId:String?
   
}
class LoggingViewController: UIViewController {
   
  var entryviewcontroller:EntryViewController? 
   
  @IBOutlet weak var eventTextBox: UITextField!
  @IBOutlet weak var datePicker: UIDatePicker!
  @IBOutlet weak var notesTextBox: UITextField!
   
  @IBAction func saveEntryButton(_ sender: Any) {
  
     if entryviewcontroller == nil {
       entryviewcontroller = EntryViewController()
     }
   
     let dateFormatter = DateFormatter()
     dateFormatter.dateFormat = "dd/MM/yyyy hh:mm a"
     entryviewcontroller?.event = self.eventTextBox.text ;
     entryviewcontroller?.message = self.notesTextBox.text
     entryviewcontroller?.dateAndTime = dateFormatter.string(from: self.datePicker.date)
     
     let db = Firestore.firestore()
     guard let uid = Auth.auth().currentUser?.uid else {
       return
     }
     
     db.collection("usersEvents").document(uid).setData([
       "event" : entryviewcontroller!.event! ,
       "dateAndTime" : entryviewcontroller!.dateAndTime!,
       "message" : entryviewcontroller!.message!]){
         
         err in
         if let err = err {
           print("Error writing document: \(err)")
           return
         } else {
           print("Document successfully written!")
         }
       }
    func viewDidLoad() {
      super.viewDidLoad()
    }
  }
   }
   
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()
         }
    }
    
}
    
}

This is the class thats being developed for the dashboard page of the application. The following error messages are displayed

Value of type '[EntryViewController]' has no member 'event'

Value of type '[EntryViewController]' has no member 'dateAndTime'

Value of type '[EntryViewController]' has no member 'message'

This is where the errors keep appearing

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

Replies

You asked the same question in your other post.

So, same answer.

Your code:

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 (not reminders with an s)

  • idem with reminders.message : reminder.message
  • idem with reminders.event : reminder.event

Please clarify.

Thank you for the reply, apologies I did not see your response on my other post and I am new to the language. I am unsure of what you mean by call reminders[someIndex].dateAndTime or more probably reminder.dateAndTime (not reminders with an s).

When i change

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)

to this

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

I just get a bunch of errors. I am not sure if I understand what it is your saying to do or if I have missed a step

Thanks for feedback. Don't forget to close the other thread BTW.

I just get a bunch of errors. 

Please tell what errors, otherwise it is information of no use.

let reminder = Reminder()

What is Reminder ? A struct or a class ? Please show its declaration and properties. Has it a dateAndTime property for instance ?

I understand now that those lines of code are from here:

            if let reminderDict = snapshot.value as? [String:AnyObject] {
                for (_,reminderElement) in reminderDict {
                    print(reminderElement);
                    let reminder = Reminder()
                    reminder.event = reminderElement["event"] as? String
                    reminder.dateAndTime = reminderElement["data and time"] as? String
                    reminder.message = reminderElement["notes"] as? String
                    self.reminders.append(reminder)
                }

DON'T REPLACE

let reminder = Reminder()

with

let reminder = reminders

That would lead to the same initial errors.

  • What is the real type of reminderElement ?

-> If you do not cast to a real type, but leave it defined as AnyObject, you cannot call:

reminderElement["event"]
  • Is reminderElement a dict itself ? Such as [String: Any] ? That's what I guess from the code.
  • If so, cast reminderElement from AnyObject to dictionary [String: Any].
  • Is dateAndTime String or String? (optional). If dateAndTime is a non optional String, then you need to unwrap.

All this could lead to the following code:

if let reminderDict = snapshot.value as? [String:AnyObject] {
    print(reminderDict)       // Just to check
    for (_,reminderElement) in reminderDict {
        if let remindIt = reminderElement as? [String: Any] {    // Cast AnyObject to [String: Any]
            let reminder = Reminder()
            reminder.event = remindIt["event"] as? String
            // if event non optional String, replace with
            // reminder.event = (remindIt["event"] as? String) ?? ""
            
            reminder.dateAndTime = remindIt["data and time"] as? String // <<-- Is the key data and time or date and time ?
            // if dateAndTime non optional String, replace with
            // reminder.dateAndTime = (remindIt["data and time"] as? String) ?? ""
            
            reminder.message = remindIt["notes"] as? String
            // if message non optional String, replace with
            // reminder.message = (remindIt["notes"] as? String) ?? ""
            
            self.reminders.append(reminder)
        }
    }
}

I have made these changes to the code

  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] {
        print(reminderDict)    // Just to check
        for (_,reminderElement) in reminderDict {
          if let remindIt = reminderElement as? [String: Any] {  // Cast AnyObject to [String: Any]
            let reminder = Reminders
            reminder.event = (remindIt["event"] as? String) ??
            reminder.dateAndTime = (remindIt["data and time"] as? String) ?? // <<-- Is the key data and
            reminder.message = (remindIt["notes"] as? String) ??
            self.reminders.append(reminder)
          }
        }
      }
   
    }, withCancel: { (error) in
      print(error.localizedDescription)
       
    })
   

However I keep getting the error messages

let reminder = Reminders

Cannot find 'Reminders' in scope

and

self.reminders.append(reminder)

Cannot convert value of type '()' to expected argument type 'String'

I am unsure of what the " let reminder = Reminders:" is meant to be. I assume that it connects and stores the variables however I am unsure. It has been the biggest problem I have faced so far and just cant wrap my head around it.