ios - 为什么我的数组加载但我的 tableView 会崩溃,索引超出空数组的范围?

标签 ios objective-c

这是我的错误:

-[__NSArrayM objectAtIndex:]: index 12 beyond bounds for empty array

我知道这个错误意味着我正在尝试访问一个“空数组”。

这个错误只发生在 viewX 从 viewY 弹回时。当您在 viewY 中的导航栏上按下“后退按钮”并立即滚动 tableView 时,它会崩溃并导致此错误。我正在使用 RETableViewManager加载我的 tableView。

在viewX的viewDidLoad中:

[[RACSignal combineLatest:@[RACObserve(self, record), RACObserve(self, restaurant)]] subscribeNext:^(id x) {
       [self setupItems];
    }];

在 setupItems 中:

RecordManager *recordManager = [[EZRecordManager alloc] initWithRecord:self.record restaurant:self.restaurant sender:self.navigationController];
self.items = [recordManager items];
self.section = [RETableViewSection section];
[self.items each:^(id data) {
    if ([data isKindOfClass:[NSString class]]) {
        self.navigationItem.title = (NSString *)data;
    } else {
        [self registerItem:[data class]];
        [self.section addItem:data];
    }
}];

[self.manager addSection:self.section];
[self.tableView reloadData];

我 NSLogged 我的数组“self.items”。这是根据方法记录的内容:

viewDidAppear - (
"\U5df2\U8a02\U4f4d\Uff0c\U5c1a\U672a\U7528\U9910",
"<REReservationHeaderItem: 0x14015b0b0>",
"<REAttributedStrItem: 0x14015b1b0>",
"<REAttributedStrWithNextItem: 0x140191a70>",
"<REAttributedStrItem: 0x140193f60>",
"<RESpacerItem: 0x140194870>",
"<REAttributedStrWithNextItem: 0x14019ce10>",
"<REAttributedStrItem: 0x140199230>",
"<RESpacerItem: 0x1401a04e0>",
"<REActionItem: 0x14019e490>",
)

NSLog 在 setupItems 中记录相同的数组,所以我知道该数组仍然存在,因为 self.item 被保存为一个属性:

@property (nonatomic, strong) NSArray *items;

所以这个算法在我第一次加载 viewX 时按预期工作,但是一旦我进入另一个 View (viewY)并按下 viewY 上的“后退按钮”以弹出到 viewX 然后立即滚动,它因上述错误而崩溃。如果我等一秒钟(甚至半秒钟),viewX 将正常工作并且没有问题。我知道这是次要的,但我的总理强调这不应该发生。我该如何解决这个问题?

错误发生的方法(RETableViewManager库的一部分):

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{ RETableViewSection *section = [self.mutableSections objectAtIndex:indexPath.section]; RETableViewItem *item = [section.items objectAtIndex:indexPath.row];

UITableViewCellStyle cellStyle = UITableViewCellStyleDefault;
if ([item isKindOfClass:[RETableViewItem class]])
    cellStyle = ((RETableViewItem *)item).style;

NSString *cellIdentifier = [NSString stringWithFormat:@"RETableViewManager_%@_%li", [item class], (long) cellStyle];

Class cellClass = [self classForCellAtIndexPath:indexPath];

if (self.registeredXIBs[NSStringFromClass(cellClass)]) {
    cellIdentifier = self.registeredXIBs[NSStringFromClass(cellClass)];
}

if ([item respondsToSelector:@selector(cellIdentifier)] && item.cellIdentifier) {
    cellIdentifier = item.cellIdentifier;
}

RETableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

void (^loadCell)(RETableViewCell *cell) = ^(RETableViewCell *cell) {
    cell.tableViewManager = self;

    // RETableViewManagerDelegate
    //
    if ([self.delegate conformsToProtocol:@protocol(RETableViewManagerDelegate)] && [self.delegate respondsToSelector:@selector(tableView:willLoadCell:forRowAtIndexPath:)])
        [self.delegate tableView:tableView willLoadCell:cell forRowAtIndexPath:indexPath];

    [cell cellDidLoad];

    // RETableViewManagerDelegate
    //
    if ([self.delegate conformsToProtocol:@protocol(RETableViewManagerDelegate)] && [self.delegate respondsToSelector:@selector(tableView:didLoadCell:forRowAtIndexPath:)])
        [self.delegate tableView:tableView didLoadCell:cell forRowAtIndexPath:indexPath];
};

if (cell == nil) {
    cell = [[cellClass alloc] initWithStyle:cellStyle reuseIdentifier:cellIdentifier];

    loadCell(cell);
}

if ([cell isKindOfClass:[RETableViewCell class]] && [cell respondsToSelector:@selector(loaded)] && !cell.loaded) {
    loadCell(cell);
}

cell.rowIndex = indexPath.row;
cell.sectionIndex = indexPath.section;
cell.parentTableView = tableView;
cell.section = section;
cell.item = item;
cell.detailTextLabel.text = nil;

if ([item isKindOfClass:[RETableViewItem class]])
    cell.detailTextLabel.text = ((RETableViewItem *)item).detailLabelText;

[cell cellWillAppear];

return cell;

最佳答案

通常当“稍等片刻就能解决问题”时,那是因为您遇到了异步问题。

首先要检查的东西:

确保在您返回时调用重新加载代码。也许您的 tableview 没有被清空,但是数组被清空了。向后移动可让您滚动旧内容(仍在加载),但委托(delegate)方法将无法创建新单元格,因为数组现在为空。

如果您等待,您的异步方法会完成它的工作,并且数组现在又满了,这使得一切正常。

可能的解决方案:

清空然后在 viewWillAppear 中重新加载 TableView 。这将导致 tableview 变空然后又变满的视觉闪光。它还会将您滚动到第一个元素。话虽这么说,它真的很简单和快速,并且使用旋转器它会显得更加流畅。

其他可能的解决方案:

离开页面后保持加载的数据,这样当您返回时它仍然存在。您可以使用任何可以在应用程序中保持数据加载的内容。它可以是一个保持实例化的单例类,或者保存在数据库中并从中重新加载(这比直接从互联网加载快得多),或者您能想到的任何东西。

关于ios - 为什么我的数组加载但我的 tableView 会崩溃,索引超出空数组的范围?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34990368/

相关文章:

objective-c - @class 与#import

iphone - 如何将 View 添加到页面控件

ios - 将 NSArray 放入 TableView

objective-c - 未收到 NSApplicationWillTerminateNotification

iphone - 如何在 UITableView 中进行就地编辑?

ios - 如何在 iOS App 的所有 View Controller 中重用相同的 UIView

ios - 使用 Core Animation 的 UIView 翻转动画

ios - Apple 证书和配置文件 - 它们何时过期?

ios - 没有任何第三方支付处理器的Apple Pay沙盒环境测试

ios - uipageViewController 没有加载 y=0 的 View