0

I have a table view with more than 1000 cells (I display about 10 on the screen). Following a "filter" action by the user I want to remove about 80% of them, then after a second filter another 80%. When working with 100 cells it's roughly instantaneous but with a 1000 it takes 0.5 seconds to finish the method [tableView endUpdates] and this totally destroys the user experience.

I create the array of Index Paths like this:

for (int i=1; i<[appDelegate.myArray count]; i++) {   //more than 1000 objects in myArray
    if (![[appDelegate.myArray objectAtIndex:i] myTest]) {  //myTest returns a BOOL 
        [appDelegate.rowsToDelete addObject:[NSIndexPath xxxxx]]; //the index path of the object that just failed the test and must be removed];
 }
}
[self.myTableViewController.tableView deleteRowsAtIndexPaths:appDelegate.rowsToDelete withRowAnimation:UITableViewRowAnimationRight];

I have tried 2 solutions, one is threading so that my user can see other parts of the UI moving whist the tableView is updating. But if he launches another level of filtering this often results in the long wait if not a crash.

I have also tried to remove the first few cells (those on the screen) and then just remove the other objects that have failed the test from the datasource without removing their corresponding cells from the tableView as they are out of sight. This gives the good, rapid result, but I then get problems with the number of rows such as:

'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (94) must be equal to the number of rows contained in that section before the update (927), plus or minus the number of rows inserted or deleted from that section (0 inserted, 215 deleted).'

Has anybody had such a performance issue? ways to solve it? Cheers, CD

4

3 回答 3

0

您可能只想使用新的行数进行过滤并重新加载整个表格视图。如果它们最终看不见,那么做所有这些删除动画是没有意义的。或者只是找出哪个部分是可见的,然后只加载和删除当前对用户可见的那些行?

于 2011-02-01T13:49:59.673 回答
0

尝试缓存属性并为您的循环使用快速枚举:

//int i = 0;
NSMutableArray *rowsToDelete = appDelegate.rowsToDelete;
for(id current in appDelegate.myArray) {
    if([current myTest]) [rowsToDelete addObject:[NSIndexPath ...]];
    //++i;
}
[self.myTableViewController.tableView deleteRowsAtIndexPaths:rowsToDelete withRowAnimation:UITableViewRowAnimationRight];

如果您使用项目的索引来创建 NSIndexPath,请取消注释第一行和第五行。另外,我注意到在您的代码中,您从 i=1 开始。由于 NSArrays 从 0 开始,这永远不会删除第一个单元格。如果你真的想要这个,将 i = 0 更改为 i = 1。

于 2010-12-15T21:37:25.867 回答
0

我同意@futureelite7 的观点,即您应该重新加载数据源而不是操纵视图。我在这里提出了一个类似问题的解决方案。

基本思想是调用 reloadSections:withRowAnimation: 并在您的 UITableViewDataSource 方法中打开分段控件的 selectedSegmentIndex。

假设您的数据是平坦的(只有一个部分),它看起来像这样:

- (IBAction)segmentSwitch:(id)sender
{
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    switch (self.segmentedControl.selectedSegmentIndex)
    {
        default:
        case 0:
            return [self.allRows count];
        case 1:
            return [self.onlySomeRows count];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id data;
    switch (self.segmentedControl.selectedSegmentIndex)
    {
        default:
        case 0:
            data = [self.allRows objectAtIndex:[indexPath row]];
            break;
        case 1:
            data = [self.onlySomeRows objectAtIndex:[indexPath row]];
            break;
    }

    //TODO: use data to populate and return a UITableViewCell...
}
于 2012-08-03T22:26:18.083 回答