Would like to ask for some help in retrieving reminders. Seems like numberOfRowsInSection and is getting called even before eventStore.fetchReminders has finished. Here is my code:
override func viewWillAppear(_ animated: Bool) {
print("****viewWillAppear")
super.viewWillAppear(true)
self.eventStore = EKEventStore()
self.reminders = [EKReminder]()
//Added to initialize
self.reminders.removeAll()
self.eventStore!.requestAccess(to: EKEntityType.reminder, completion:
{(granted, error) in
if granted
{
let predicate = self.eventStore.predicateForReminders(in: nil)
self.eventStore.fetchReminders(matching: predicate, completion: { (reminders: [EKReminder]?) -> Void in
self.reminders = reminders
DispatchQueue.main.async() {
//Added
self.reminders = reminders
self.tableView.reloadData()
}
})
}
else
{
print("The app is not permitted to access reminders, make sure to grant permission in the settings and try again")
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("*****numberOfRowsInSection")
print("numberOfRowsInSection reminders \(self.reminders.count)")
return self.reminders.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
print("****titleForHeaderInSection")
print("titleForHeaderInSection reminders \(self.reminders.count)")
return "test"
}
I tried putting it in viewDidLoad but same thing happens, the self.reminders.count in numberofRowsInSection is returning 0. I also tried to call fetchReminders OUTSIDE of requestAccess (because I thought requestAccess was not firing), but I end up with the same thing. Is there anything I'm doing wrong? Would really appreciate any advise!
Thanks!
This is normal. The UITableViewController
attempts to display the contents of the table view as the view controller is being shown. You should initialize self.reminders
with an empty array at the start of viewDidLoad
so the table view initially shows no results.
Then, once your access of the event store is complete, your code to reset self.reminders
and reload the table view will be called.
One critical change you should make is to set self.reminders
inside the DispatchQueue.main.async()
block. This ensures the data source is updated just before the table is reloaded and not before hand. In other words, update your code to:
self.eventStore.fetchReminders(matching: predicate, completion: { (reminders: [EKReminder]?) -> Void in
DispatchQueue.main.async() {
self.reminders = reminders
self.tableView.reloadData()
}
})
One other change to consider is to initially set self.reminders
to nil
and have your table view data source methods treat this as a signal to show one row that says "loading" (or something similar). Otherwise your users may wonder why they are starring at a mostly blank screen for a brief period of time.