Reputation: 721
I am trying to load data into a Table View with Swift. My problem is that the displaying of the data takes a good 10-15 seconds. The data does end up getting displayed, but it just takes to long of a time. I am retrieving events from iCal and then displaying them in a table view. Is there a problem with the code?
class EventsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var eventCounterLabel: UILabel!
@IBOutlet weak var tableView: UITableView!
var eventStore = EKEventStore()
var calendar: EKCalendar?
var events = NSMutableArray() as NSMutableArray
var times = NSMutableArray() as NSMutableArray
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//Table View Data Source and Delegate
self.tableView.delegate = self
self.tableView.dataSource = self
//Event Kit access
eventStore.requestAccessToEntityType(EKEntityTypeEvent,
completion: {(granted: Bool, error:NSError!) in
if !granted {
println("Access to store not granted")
}else{
self.getTheCalendar()
}
})
}
//Event Kit Methods
func getTheCalendar(){
//Set the start and finish dates for events
let start = NSDate() as NSDate
let finish = NSDate() as NSDate
//Make the predicate
let eventPredicate = self.eventStore.predicateForEventsWithStartDate(start, endDate: finish, calendars: nil) as NSPredicate
self.eventStore.enumerateEventsMatchingPredicate(eventPredicate, usingBlock: { (event: EKEvent!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
if event != nil{
self.events.addObject(event.title)
self.times.addObject(event.startDate)
}
//Set the event counter label
if self.events.count == 1{
self.eventCounterLabel.text = "You have " + "\(self.events.count)" + " event today."
}else{
self.eventCounterLabel.text = "You have " + "\(self.events.count)" + " events today."
}
//Reload the table view
self.tableView.reloadData()
})
}
//Table View Methods
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.events.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:EventsTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as EventsTableViewCell
//Set the event label
cell.eventLabel.text = (self.events.objectAtIndex(indexPath.row) as String)
cell.eventLabel.adjustsFontSizeToFitWidth = true
//Set the event time label
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate:self.times.objectAtIndex(indexPath.row) as NSDate)
let hour = components.hour as Int
var theHourOfTheEvent = hour
if theHourOfTheEvent < 12{
if theHourOfTheEvent == 0{
cell.eventTimeLabel.text = "All Day"
}else{
cell.eventTimeLabel.text = "\(theHourOfTheEvent)" + " am"
}
}else if theHourOfTheEvent > 12 && theHourOfTheEvent < 24{
theHourOfTheEvent -= 12
cell.eventTimeLabel.text = "\(theHourOfTheEvent)" + " pm"
}else if theHourOfTheEvent == 24{
theHourOfTheEvent -= 12
cell.eventTimeLabel.text = "\(theHourOfTheEvent)" + " am"
}else if theHourOfTheEvent > 24{
theHourOfTheEvent -= 24
cell.eventTimeLabel.text = "\(theHourOfTheEvent)" + " am"
}else if theHourOfTheEvent == 12{
cell.eventTimeLabel.text = "\(theHourOfTheEvent)" + " pm"
}
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100.0
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
Upvotes: 0
Views: 433
Reputation: 42872
You are reloading the table view inside the EventKit enumerator.
self.eventStore.enumerateEventsMatchingPredicate(eventPredicate, usingBlock: {
...
self.tableView.reloadData()
})
This means you reload it once for each retrieved event in the calendar - which is likely to be a lot of un-necessary reloads, and slow.
You should only call this function once, after all the events are collected. Move it outside the loop and you should see an improvement.
self.eventStore.enumerateEventsMatchingPredicate(eventPredicate, usingBlock: {
...
})
self.tableView.reloadData()
You may also want to call it in a dispatch block on the main thread; Calls to change the UI should always be on the main thread, and it's unclear from your example what thread is executing the code.
Alternatively, you might want to add the elements to the table as soon as you get them - in this case, don't use reloadTable
, but use insertRowsAtIndexPaths
as you get the new data. This is cheaper than calling reloadData every time, since it doesn't visit every cell - and in fact will only visit on-screen cells, which is cheap assuming you add new events to the end of the list (not the start).
Upvotes: 2