I have a segmented control being used as a toggle. When toggled, I switch a bunch of contents around in a table view which takes a tiny but noticeable amount of time (inserting/deleting sections in the table view, animating the change, etc). I want the segmented control to respond to the selection immediately. So in my action handling code for the segmented control's UIControlEventValueChanged event, I do the following:
- (IBAction)groupingChanged:(id)sender {
UISegmentedControl *seg = sender;
[tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex];
[self performSelectorOnMainThread:@selector(updateGrouping)
withObject:nil
waitUntilDone:NO];
}
Where updateGrouping
is:
- (void)updateGrouping {
MXAssertMainThread();
[tableView beginUpdates];
... several table updates
[tableView endUpdates];
}
Setting waitUntilDone:NO
allows the groupingChanged
method to complete before the updateGrouping
is called, but this doesn't seem to be sufficient to repaint the view. The segmented control sticks until the table is done updating, then it switches over.
So I tried modifying groupingChanged:
to create a thread for the update like so:
- (void)delayed {
[self performSelectorOnMainThread:@selector(updateGrouping)
withObject:nil
waitUntilDone:NO];
}
- (IBAction)groupingChanged:(id)sender {
UISegmentedControl *seg = sender;
[tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex];
[self performSelectorInBackground:@selector(delayed) withObject:nil];
}
And this does work. The segmented control toggles instantly and the table soon follows. But I'm not at all confident of the result. Is it simply a side-effect of giving the main thread a reprieve while the new thread started up? Is this just how I need to queue updates to the UI? It's clearly hacky. I'm hoping someone has a better pattern they're following for this situation.