用UISwitch显示和隐藏UITableViewCell过快崩溃

我有一个UITableView向用户展示一些设置。 除非UISwitch处于“On”位置,否则某些单元将被隐藏。 我有以下代码:

- (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]; } 

这按预期工作,直到我快速连续两次切换UISwitch(通过双击),在这种情况下,应用程序崩溃

 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. 

我知道这是由于numberOfRowsInSection的错误返回值造成的,因为当单元格animation还在播放的时候,开关回到原来的位置。 我试过禁用切换和挂钩其他事件处理程序下的代码,但似乎没有防止崩溃。 使用reloadData而不是animation也解决了问题,但我更喜欢漂亮的animation。

有没有人知道一个正确的方法来实现呢?

另一个(更优雅的)解决scheme是这样的:

我用这种方法修改了Alan MacGregor - (IBAction)SwitchDidChange:(id)sender方法:

 - (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]; } } 

其他部分保持不变。

只需将开关的enabled属性设置为NO直到更新完成。

我有我的这个问题,避免崩溃的方式是不明确使用uiswitch,而是将信息中继到布尔值,inheritance人如何做到这一点。

将布尔值添加到实现文件的顶部

 bool _showRows = NO; 

更新你的uiswitch代码

 - (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]; } } 

最后更新你的numberOfRowsInSection

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

UIControlEventValueChanged事件即使在控件的值没有真正改变时也会发生。 所以togglePush即使在交换机的值没有改变时也会被调用。 当您快速切换开关时,您可能不会总是从开>关>开>关等,可以关>开>开>关。

所以发生了什么事情是你连续得到两个连续的两个insertSections。 这显然是不好的。

为了解决这个问题,你需要记住button以前的状态(可能是一个ivar),如果新值(source.on)与以前的值不同,只执行插入(或删除)。