Ios 为什么有时会在节中的行数之前调用索引路径中的行高度?

Ios 为什么有时会在节中的行数之前调用索引路径中的行高度?,ios,tableview,realm,Ios,Tableview,Realm,我有这个密码 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { UnlockTableSectionHeaderType type = (UnlockTableSectionHeaderType) [self.sections[section] integerValue]; switch (type) { case UnlockTab

我有这个密码

- (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
类似于负责从web和领域查询数据的控制器)

这是我的日志

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)
但不知何故,
numberOfRowsInSection
没有被调用

它在这一排崩溃了

return [self.topicController showLoading] ? 130.0f :
                    [TopicCell heightForTopicCellForThread:[self.topicController itemForIndex:row] showCategory:YES];
我怎样才能解决这个问题? 谢谢

更新

现在看看stacktrace,很抱歉之前没有包括它,我现在不能做,因为我们已经更改了设计。通过删除主题并只保留类别,现在我们只有一种类型的控制器,崩溃消失了。。。似乎每个部分都有两种类型的数据源存在问题,当其中一种更新而另一种仍在更新时,会导致崩溃

无论如何,要了解更多信息,请从
cellforrowatinexpath
中的此行调用
heightforrowatinexpath

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;
    }

但我不知道为什么此时调用了
cellforrowatinexpath
,这是由苹果定义的。但是当你仔细想想的时候,这是有道理的。如果行数占全屏高度,则询问另一个部分的行数是没有意义的。

可以随时调用
heightForRowAtIndexPath:
cellForRowAtIndexPath:
方法,例如在滚动期间。当表视图知道基础数据已更改时,它将只调用
numberofrowsinssection:
。这就是
reloadData
调用的目的:告诉表视图数据已经更改,它需要重新初始化表

因此,更新主线程上的底层数据(在您的示例中是Realm)非常重要,然后立即调用
reloadData


您的
[self.topicController showLoading]
似乎是一种避免这样做的变通方法。这可以很好地工作,但是您需要确保更改
showLoading
状态,并在主线程上调用
reloadData

那么,委托方法的调用顺序是由Apple定义的吗?您的
topicController
做什么?尤其是在
itemForIndex:
中?这是直接委托给领域集合吗?另外,如何将更新从领域通知传播到视图控制器?这是同步发生的吗?当您调用“reloadData”时,日志不会显示。可能坠机发生在那之前?听起来很像是线程问题,你在后台线程上更新了底层数据。@marius唯一要做的事情是
itemForIndex:
return self.items[index]其中
self.items
RLMResults
。在
viewDidLoad:
中,通过从领域(如果有,它将不显示加载单元格)进行查询来初始化,并向服务器进行查询。当结果返回时,它会将数据保存到领域,并且
self上的领域通知将被委派回去并调用
reloadData
。可以理解的是,屏幕外的部分不会调用numberOfRowsInSection:。但是,也绝对不应该为这些部分调用HeightForRowatineXpath:
。调用HeightForRowatineXpath:来计算右侧滚动条的大小和位置。为此,它当然需要在HeightForRowatineXpath:之前调用numberOfRowsInSection:。也就是说,不这样做是没有意义的。没错,我还没有完全想清楚这一点。
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;
    }