Showing and hiding a UITableViewCell with a quick UISwitch crash

I have a UITableView that provides the user with some settings. Some cells are hidden if UISwitch is not in the 'On' position. I have the following code:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return switchPush.on ? 6 : 1; } // Hooked to the 'Value Changed' action of the switchPush - (IBAction)togglePush:(id)sender { NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:0]; for(int i = 1; i <= 5; i++) { [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; } [tableView beginUpdates]; if(switchPush.on) { [tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } else { [tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; } [tableView endUpdates]; } 

This works, as expected, until I switch UISwitch twice in a row quickly (by double-clicking), in which case the application will fail

 Invalid table view update. The application has requested an update to the table view that is inconsistent with the state provided by the data source. 

I know this is caused by the wrong return value of numberOfRowsInSection, as the switch returns to its original position while the cell animation is still playing. I tried to turn off the switch and connect the code to other event handlers, but nothing prevents the crash. Using reloadData instead of animation also solves the problem, but I would prefer nice animation.

Does anyone know the correct way to implement this?

+6
source share
4 answers

Another (more elegant) solution to the problem:

I modified the Alan MacGregor - (IBAction)SwitchDidChange:(id)sender method as follows:

 - (IBAction)SwitchDidChange:(UISwitch *)source { if (_showRows != source.on) { NSArray *aryTemp = [[NSArray alloc] initWithObjects: [NSIndexPath indexPathForRow:1 inSection:0], [NSIndexPath indexPathForRow:2 inSection:0], [NSIndexPath indexPathForRow:3 inSection:0], [NSIndexPath indexPathForRow:4 inSection:0],nil]; [_tblView beginUpdates]; _showRows = source.on; if (_showRows) { [_tblView insertSections:aryTemp withRowAnimation:UITableViewRowAnimationFade]; } else { [_tblView deleteSections:aryTemp withRowAnimation:UITableViewRowAnimationFade]; } [_tblView endUpdates]; } } 

The remaining parts remain unchanged.

+3
source

Just set the enabled property of your switch to NO until updates are completed.

+2
source

I had this problem on mine, and in order to avoid a crash, I should not explicitly use uiswitch, but instead pass the information to a logical one, this is how I did it.

Add a boolean to the top of the implementation file

 bool _showRows = NO; 

Update your uiswitch code

 - (IBAction)SwitchDidChange:(id)sender { NSArray *aryTemp = [[NSArray alloc] initWithObjects:[NSIndexPath indexPathForRow:1 inSection:0], [NSIndexPath indexPathForRow:2 inSection:0], [NSIndexPath indexPathForRow:3 inSection:0], [NSIndexPath indexPathForRow:4 inSection:0],nil]; if (_showRows) { _showRows = NO; _switch.on = NO; [_tblView deleteRowsAtIndexPaths:aryTemp withRowAnimation:UITableViewRowAnimationTop]; } else { _showRows = YES; _switch.on = YES; [_tblView insertRowsAtIndexPaths:aryTemp withRowAnimation:UITableViewRowAnimationBottom]; } } 

Finally, update your NumberOfRowsInSection

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section == 0) { if (_showRows) { return 5; } else { return 1; } } return 0; } 
+2
source

UIControlEventValueChanged events occur even when the control value does not actually change. therefore, togglePush is called even when the value of the switch does not change. when you quickly switch the switch, you may not always switch to> off. > incl. > off etc., then you can disable> on> on> off.

so it happens that you get two rows in a row, causing two inserts one after another. which is clearly bad.

to fix this, you need to remember what was in the previous state of the button (possibly in ivar) and only perform insertion (or deletion) if the new value (source.on) is different from the previous value.

0
source

Source: https://habr.com/ru/post/907834/


All Articles