为什么有时在numberOfRowsInSection之前调用heightForRowAtIndexPath?

时间:2016-07-26 10:36:24

标签: ios tableview realm

我有这段代码

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    UnlockTableSectionHeaderType type = (UnlockTableSectionHeaderType) [self.sections[section] integerValue];
    switch (type) {
        case UnlockTableSectionTypeAllLeaderBoard:
            return 1;
        case UnlockTableSectionTypeTopic:
            NSLog(@"%@", [self.topicController showLoading] ? @"YES" : @"NO");
            NSLog(@"%d", [self.topicController loadedItemCount]);
            return [self.topicController showLoading] ? 1 : [self.topicController loadedItemCount];
        case UnlockTableSectionTypeCategory:
            return [self.categoryController showLoading] ? 1 : [self.categoryController loadedItemCount];
        default:
            return 0;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return [UnlockTableSectionHeaderView defautHeight];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    UnlockTableSectionHeaderType type = (UnlockTableSectionHeaderType) [self.sections[indexPath.section] integerValue];
    NSInteger row = indexPath.row;

    switch (type) {
        case UnlockTableSectionTypeAllLeaderBoard:
            return 207.0f;
        case UnlockTableSectionTypeTopic:
            NSLog(@"heightForRow %@", [self.topicController showLoading] ? @"YES" : @"NO");
            NSLog(@"heightForRow %d", [self.topicController loadedItemCount]);
            return [self.topicController showLoading] ? 130.0f :
                    [TopicCell heightForTopicCellForThread:[self.topicController itemForIndex:row] showCategory:YES];
        case UnlockTableSectionTypeCategory:
            return 120.0f;
    }
    return 0.0f;
}

尝试使用控制器显示数据(Controller就像负责来自网络和领域的查询数据一样)

这是我有的日志

Sent message: 41|{"id":51,"m":"group.getAllUnlock","p":[{"limit":15,"skip":0}]} <-- call to server
Sent message: 41|{"id":52,"m":"thread.queryUnlock","p":[{"limit":15,"skip":0}]} <-- call to server
YES
0
heightForRow YES
heightForRow 0
YES
0
heightForRow YES
heightForRow 0
YES
0
heightForRow YES
heightForRow 0
YES
0
heightForRow YES
heightForRow 0
heightForRow YES
heightForRow 0
heightForRow YES
heightForRow 0
YES
0
heightForRow YES
heightForRow 0
YES
0
heightForRow YES
heightForRow 0
Got response for RPC call 52, 34 bytes <-- response from server
Zip size: 838
Got response for RPC call 51, 3087 bytes <-- response from server
heightForRow NO <-- Height For Row called first
heightForRow 0
WARNING: GoogleAnalytics 3.10 void GAIUncaughtExceptionHandler(NSException *) (GAIUncaughtExceptionHandler.m:49): Uncaught exception: Index 0 is out of bounds (must be less than 0)

正如您所看到的,当我从服务器获取数据时,我更新了结果,并使用领域通知对该方法进行委托调用

- (void)controllerDidReloadData:(BaseController *_Nonnull)controller {
    [self.tableView reloadData];
}

但不知怎的numberOfRowsInSection没有被叫......

它在这一行崩溃

return [self.topicController showLoading] ? 130.0f :
                    [TopicCell heightForTopicCellForThread:[self.topicController itemForIndex:row] showCategory:YES];

我该如何解决这个问题? 感谢

更新

现在看看堆栈跟踪抱歉没有包含它,我现在不能这样做,因为我们已经改变了设计。通过删除主题并仅留下类别,所以现在我们只有一种类型的控制器并且崩溃已经消失...似乎是每个部分有两种类型的数据源的问题,当其中一个更新而另一个仍在更新它会导致崩溃。

无论如何,有关heightForRowAtIndexPath

中此行调用cellForRowAtIndexPath的更多信息
if (type == UnlockTableSectionTypeTopic) {
        if ([self.topicController showLoading]) {
            return [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([LoadingTableViewCell class]) forIndexPath:indexPath];
        }
        // Below line is the line which called `heightForRowAtIndexPath` when looking into the stacktrace
        TopicCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([TopicCell class]) forIndexPath:indexPath];
        cell.delegate = self;
        [cell configureCellForThread:[self.topicController itemForIndex:row]
                            lastCell:row == [self.topicController loadedItemCount] - 1
                        showCategory:YES];
        return cell;
    }

但我不知道为什么此时调用cellForRowAtIndexPath

2 个答案:

答案 0 :(得分:0)

可以随时调用heightForRowAtIndexPath:cellForRowAtIndexPath:方法,例如在滚动期间。表视图仅在知道基础数据已更改时才会调用numberOfRowsInSection:。这就是reloadData调用的用途:告诉表视图数据已更改,并且需要重新初始化表。

因此,在主线程上更新基础数据(在您的案例中为Realm)非常重要,然后立即调用reloadData

您的[self.topicController showLoading]似乎是一种解决办法,以避免不得不这样做。这可以正常工作,但是您需要确保更改showLoading状态并在主线程上直接调用reloadData

答案 1 :(得分:-1)

这是由apple定义的。但是当你想到它时 - 它是有道理的。如果它们占据全屏高度,则询问另一部分的行数是没有意义的。