iOS:UITableView重新加载数据在滚动之前不起作用

4
我注意到在SO上有一些类似这个问题的提问,但是它们似乎都以用户正在打电话结束。
 [self.tableView reloadData]

除了主线程外。

我的问题是,我在主UI线程上调用它,但我直到我轻触屏幕或稍微滚动一下才会加载新行。这是我正在做的:当我进入我的ViewController时,表格完全并且正确地显示。在视图上按下按钮后,我调用我的外部数据库,并加载一些新行添加到表中。将这些添加到我的数据源后,我调用reloadData,并且所有新行都为空白。仍然适合屏幕并已经是表格的一部分的几行仍然显示,但没有任何新内容。当我触摸屏幕或稍微滚动一下时,所有新单元格都会跳出来。

以下是从服务器完成我的调用的代码:

     - (void)connectionDidFinishLoading:(NSURLConnection *)connection {

if(connection == self.searchConnection) {

 ..... some code ......

    if(successful) {
        // Adding new data to the datasource
        [self.locations removeObjectAtIndex:[[NSNumber numberWithInt:self.locations.count - 1] integerValue]];
            [self.cellTypeDictionary removeAllObjects];
            for(int i = 0; i < [jsonLocations count]; ++i) {
                NSDictionary *locationDictionary = jsonLocations[i];
                BTRLocation *location = [BTRLocation parseLocationJSONObject:locationDictionary];
                [self.locations addObject:location];
            }


        if(self.currentNextPageToken != nil && ![self.currentNextPageToken isEqual:[NSNull null]] && self.currentNextPageToken.length > 0) {
            BTRLocation *fakeLocation = [[BTRLocation alloc] init];
            [self.locations addObject:fakeLocation];
        }

        [self determineCellTypes];
        if([self.locations count] < 1) {
            self.emptyView.hidden = NO;
        } else {
            ... some code .....

            if(self.pendingSearchIsNextPageToken) {
                NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[[NSNumber numberWithInt:countBefore] integerValue]

                                                            inSection:[[NSNumber numberWithInt:0] integerValue]];

                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
                });
            } else {
                NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[[NSNumber numberWithInt:0] integerValue]
                                                            inSection:[[NSNumber numberWithInt:0] integerValue]];

                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
                });
            }
        }
    } else {
        if(invalidAccessToken) {
            // TODO: invalidAccessToken need to log out
        }
    }

你可以看到,我甚至添加了HTML标签。
  dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
                });

尽管我知道connectionDidFinishLoading在主线程上被调用,但我还是想试一试。我看不出这为什么不起作用。

你在调用 reloadData 的时候验证了 self.tableView 不是 nil 吗? 你验证了 tableView:numberOfRowsInSection: 返回的数量是否正确(即不为零)吗? 你验证了你的数据源(我假设是 self.locations?)是否包含数据? 你验证了 self.tableView.frame 是否正确,并且它实际上在当前的 UIWindow 中(例如,self.tableView.superview 不是 nil)吗? - i_am_jorf
self.tableView 不为 nil,numberOfRowsInSection 返回正确的数量 - 它从 20 变成了 40,self.locations 包含 40 个对象,它们都是我所期望的,而且 self.tableView.superview 绝对不是 UIWindow,它是应该的。 - user1513171
问题似乎是在调用reloadData之后,cellForIndexPath并没有为我添加的任何新单元格调用,尽管其中至少有一到两个单元格应该被调用,因为它们不在视图中。 - user1513171
1个回答

1

the proper way is:

[self.tableView reloadData];
__weak MyViewController* weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
                 __strong MyViewController *strongSelf = weakSelf;
                [strongSelf.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
            });

有时候我发现你在reloadData之后添加了一些内容:
[self.tableView layoutIfNeeded];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接