mazz0
mazz0

Reputation: 715

UITableView - how do you reload with completely new data?

I've got a table view showing the output of a search. When I update it to show the output of a totally different search if the old set of results was longer then old cells remain below my new ones.

For examples, if my first results are:

[Sam,
Joe,
Sally,
Betty,
Bob]

then I have five cells, one per result, as expected. If my second set of results is short, say just

[Smith]

then I now have five cells (Smith, Joe, Sally, Betty and Bob), when only one (Smith) is expected.

Here's how I'm reloading:

results = getResults()
tableView.reloadData()

And here's how I'm getting the number of cells:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if results != nil {
        println("Table has \(results!.count) rows.")
        return results!.count
    }
    println("Table is empty.")
    return 0
}

which is printing out "Table has 1 rows." as expected, but the four old rows are still there.

Now, I could delete them before reloading, or delete the whole section, but is there a better way of achieving this? I thought reloadData would reload everything.


Additional Info

Here's cellForRowAtIndexPath as requested:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("SearchEventsCell", forIndexPath: indexPath) as SearchEventsCell
    if results != nil && eventStore != nil && results!.count >= indexPath.row {
        let event = results![indexPath.row] as EKEvent
        cell.configureCellWithEvent(event)
    }
    else {
        println("Couldn't dequeue the cell")
    }
    return cell
}

And just to prove we have the right number of rows I put a println in before reloadData():

println("We're about to reload the table view, we have \(numberOfSectionsInTableView(tableView)) sections and \(tableView(tableView, numberOfRowsInSection:0)) rows in section 0")
tableView.reloadData()

Which outputs

Table has 1 rows.
We're about to reload the table view, we have 1 sections and 1 rows in sections 0
Table has 1 rows.

as it should.

Something else I've noticed, which surely has to be related - the table doesn't update at all until I try scrolling. What am I missing? I know reloadData has been called as println is being called within numberOfRowsInSection.


Update

The textFieldShouldReturn method that triggers the update includes this code:

eventStore.requestAccessToEntityType(EKEntityTypeEvent,
    { accessGranted, error in
        if accessGranted {
            if let searchEventsController = self.searchEventsController {
                searchEventsController.search(self.searchTextField.text)
            }
        }
        else {
            self.accessDenied()
        }
    }
)

which seems very likely to be the culprit. Is there a better way of checking for permission? I included it there so that if the user ever disallowed it it would ask again next time they try to use it, rather than just failing.

Upvotes: 0

Views: 499

Answers (1)

mazz0
mazz0

Reputation: 715

The problem was indeed the fact that reloadData was taking place in another thread due to the eventStore.requestAccessToEntityType call.

There are two solutions:

1) Perform the permissions check once, when the app loads, instead of every time you access the the EventStore, as suggested by Paulw11. This means for the majority of the application there's only one thread.

2) Use the following code to execute reloadData on the main thread:

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}

as suggested by almas.

Update: I've just checked and if you revoke the permission for the app to access the Calendar then it doesn't ask the user again anyway, it just denies access, so there's no reason to keep the eventStore.requestAccessToEntityType where it is.

Upvotes: 1

Related Questions