1

如果每个单元格的内容都需要大量计算,那么保持 UITableView 平滑滚动的最佳方法是什么?例如:

#define maxN 40

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return maxN;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellId = @"CellIdentifier";

    UITableViewCell *cell = nil;
    cell = [tableView dequeueReusableCellWithIdentifier:cellId];

    //customization
    int row = indexPath.row;
    int fib = [self fib:row];

    cell.textLabel.text = [NSString stringWithFormat:@"%d", fib];

    return cell;
}

- (int)fib:(int)n
{
    return (n<=2 ? 1 : [self fib:n-1] + [self fib:n-2]);
}

这适用于最大约 30 的 maxN。如果值大于该值,表格视图将在计算大数字时停止。

我知道解决方案与异步计算有关,但是您将如何设置它以保持 UI 流畅?

更新:这是更新的方法。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellId = @"FibIdentifier";

    UITableViewCell *cell = nil;

    cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    [self configureCellAtIndexPath:indexPath];

    return cell;
}

-(void)configureCellAtIndexPath:(NSIndexPath *)indexPath {

    if ([self.fibResults objectAtIndex:indexPath.row] != [NSNull null]) {
        // apply cached result
        UITableViewCell *cell = [self.fibTable cellForRowAtIndexPath:indexPath];
        cell.textLabel.text = [NSString stringWithFormat:@"%d", [(NSNumber*)[self.fibResults objectAtIndex:indexPath.row] intValue]];

        return;
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
        NSInteger row = indexPath.row;
        int fib = [self fib:row];

        //cache the result
        [self.fibResults replaceObjectAtIndex:row withObject:[NSNumber numberWithInt:fib]];

        dispatch_async(dispatch_get_main_queue(), ^(void){
            [self.fibTable reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        });
    });
}

好消息是表格滚动流畅。坏消息是单元格填充了随机值,而不是正确的 1、1、2、3、5、8 等顺序。

4

1 回答 1

2

您在后台线程中执行这些类型的操作,然后分派回主线程以更新表格视图单元格。诀窍是到那时该单元格可能已被重用,因此您需要调用-reloadRowsAtIndexPaths:withRowAnimation:而不是引用该单元格。您还应该将结果缓存在字典或其他形式的记忆中。

-(void)configureCellAtIndexPath:(NSIndexPath *)indexPath {
    if (haveCachedResult) {
        // apply cached result
        return;
    }
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH) ^{
        // perform long-running work. Cache result.
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        });
    });
}
于 2013-10-21T22:50:42.223 回答