Reputation: 715
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
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