使用来自服务器的新数据更新单元格,而无需重新加载相同的内容 - iOS

时间:2015-01-11 20:26:03

标签: ios objective-c uitableview

我有一个UITableView,它从webService加载其数据。我有一个单例对象来跟踪我的数据(NSMutableArray *)。加载新数据时,我向tableViewController发送通知并调用[self.tableView reloadData];这将重绘我的表并使用当前数据填充单元格。

我有2个问题。

  1. 如果我在重新加载数据时滚动,应用程序崩溃,因为(NSMutableArray *)在加载新数据时空了一秒钟,我得到index 4 beyond bounds for empty array

  2. 为了解决这个问题,我在调用[_myArray removeAllObjects];来修复崩溃之前完成了这个[self.tableView reloadData];,但是在再次绘制它们之前清除所有单元格一秒钟。

  3. 这不是我想达到的预期效果。我希望它像邮件App一样重新加载单元格,它将绘制和删除必要的单元格,并保留单独保留的单元格。

    我也尝试了reloadSections:withRowAnimation:UITableViewRowAnimationFade;动画重新加载,但我仍然需要在重新加载之前清空数组。

    我该怎么做?我觉得我需要创建一个数组的副本,然后移动它,我是在正确的道路上吗?这是我的重装功能。

    - (void)reloadTable:(NSNotification *)notif {
    
        [self.sellingTableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
    
    }
    

    ******* **** UPDATE

    在@oren的指导下,这就是我想出来的......这样可行,但我担心有大量数据的表,这样效率不够高。我试着编写一个散列算法来保存和索引行的比较,以减少迭代次数,但是结果集的排序总是存在差异......

    我最终有2个名单。一个是我用来填充表的单例列表。这用于代替使用SQLite 3的核心数据等本地数据存储,但这些也可用于在应用关闭时保留数据。

    当我唤醒我的应用程序或加载视图时..数据从我的单例列表中加载...然后我创建另一个数组,其中包含来自服务器的数据,检查两个数组是否相互更改,然后添加/删除行必要时。

    -(void)sortRequestList:(NSNotification *)notification
    {
        RequestManager *newListManager = [[RequestManager alloc] init];
    
        if ([notification.object isKindOfClass:[RequestManager class]])
        {
            newListManager = [notification object];//New Data that was downloaded from web
        }
        else
        {
            NSLog(@"Error, object not recognized.");
        }
    
        NSLog(@"newListManager count = %lu", (unsigned long)newListManager.requestNotFilledList.count);
        NSLog(@"Before - requestNotFilledList count = %lu", (unsigned long)self.requestManager.requestNotFilledList.count);
    
    
        NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
        NSMutableArray *deleteIndexPaths = [[NSMutableArray alloc] init];
    
        if ([self.requestManager.requestNotFilledList count] == 0)
        {
    
            [newListManager.requestNotFilledList enumerateObjectsUsingBlock:^(Request *request, NSUInteger index, BOOL *stop) {
    
    
                [self.requestManager.requestNotFilledList insertObject:request atIndex:index];
                [insertIndexPaths addObject:[NSIndexPath indexPathForRow:index inSection:0]];
    
            }];
        } else { 
    
    
            __block BOOL foundMatch;
            [self.requestManager.requestNotFilledList enumerateObjectsUsingBlock:^(Request *oldReq, NSUInteger index, BOOL *stop) {
    
                foundMatch = false;
    
                [newListManager.requestNotFilledList enumerateObjectsUsingBlock:^(Request *newReq, NSUInteger newIdx, BOOL *stop) {
    
                    if ([oldReq.requestID isEqualToString:newReq.requestID])
                    {
                        foundMatch = true;
                        *stop = YES;
                    }
    
                }];
    
                if (foundMatch == false)
                {
                    [deleteIndexPaths addObject:[NSIndexPath indexPathForRow:index inSection:0]];
                    [self.requestManager.requestNotFilledList removeObjectAtIndex:index];
                }
    
            }];
    
            [newListManager.requestNotFilledList enumerateObjectsUsingBlock:^(Request *newReq, NSUInteger index, BOOL *stop) {
    
                foundMatch = false;
    
                [self.requestManager.requestNotFilledList enumerateObjectsUsingBlock:^(Request *oldReq, NSUInteger oldIdx, BOOL *stop) {
    
                    if ([oldReq.requestID isEqualToString:newReq.requestID])
                    {
                        foundMatch = true;
                        *stop = YES;
                    }
    
                }];
    
                if (foundMatch == false)
                {
                    [insertIndexPaths addObject:[NSIndexPath indexPathForRow:index inSection:0]];
                    [self.requestManager.requestNotFilledList insertObject:newReq atIndex:index];
                }
    
            }];
    
        }
    
        NSLog(@"After - requestNotFilledList count = %lu", (unsigned long)self.requestManager.requestNotFilledList.count);
    
        UITableView *tv = (UITableView *)self.view;
    
        [tv beginUpdates];
        [tv insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
        [tv deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
        [tv endUpdates];
        [self.refreshControl endRefreshing];
    
    }
    

1 个答案:

答案 0 :(得分:1)

如何插入新的indexPaths并删除不需要的带有动画的indexPaths:

- insertRowsAtIndexPaths:withRowAnimation:
- deleteRowsAtIndexPaths:withRowAnimation:

你需要删除一个indexPaths数组,让我们假设你有一个数组[1,2,3,6]并删除2和6,你需要为行1设置数组indexPaths和3.

此外,您需要有一个要插入的indexPaths数组:让我们假设您添加a,b,c,如下所示:[a, 1 3 ,b, c ,7],因此indexPaths将用于行 - 0,3,4。

我做了一个简单的代码只是为了一个例子:我的tableView中的起始数据是[1,2,3,4,5,6],在下面的代码中我将它更新为[1, new1 ,2, new2 ,3,5, new3 ,7]。棘手的部分是计算插入和删除的indextPaths。

- (void)updateTableView
{
    [self.tableView beginUpdates];

    // First remove the objects
    [self.dataArray removeObjectAtIndex:5];
    [self.dataArray removeObjectAtIndex:3];

    NSArray *indexPathsToRemove = [NSArray arrayWithObjects:
                                   [NSIndexPath indexPathForRow:3 inSection:0],
                                   [NSIndexPath indexPathForRow:5 inSection:0], nil];

    // Insert the new ones
    [self.dataArray insertObject:@"New data 3" atIndex:4];
    [self.dataArray insertObject:@"New data 2" atIndex:2];
    [self.dataArray insertObject:@"New data 1" atIndex:1];

    NSArray *indexPathsToInsert = [NSArray arrayWithObjects:
                               [NSIndexPath indexPathForRow:1 inSection:0],
                               [NSIndexPath indexPathForRow:3 inSection:0],
                               [NSIndexPath indexPathForRow:6 inSection:0], nil];

    // Animate the insertion and deletion
    [self.tableView deleteRowsAtIndexPaths:indexPathsToRemove withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];

    [self.tableView endUpdates];

}

您总是需要在插入之前考虑删除,在动画块中通过' beginUpdats',tableView不会插入新的行或部分,直到它处理完所有删除。