PoKoBros
PoKoBros

Reputation: 721

calling self.tableView.reloadData takes 10-15 seconds

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

Answers (1)

Alex Brown
Alex Brown

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

Related Questions