3

我在使用发布配置运行时遇到了错误,这似乎是局部变量的过早发布tmp

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.'

相关代码:

@property (nonatomic, strong) NSIndexPath *selectedCellIndexPath;

...

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (_selectedCellIndexPath != nil && [_selectedCellIndexPath isEqual:indexPath]) {        
        self.selectedCellIndexPath = nil;
        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else if (_selectedCellIndexPath != nil && ![_selectedCellIndexPath isEqual:indexPath]) {

//--- problematic code
        NSIndexPath *tmp = _selectedCellIndexPath;
        self.selectedCellIndexPath = indexPath;
        [tableView reloadRowsAtIndexPaths:@[tmp, _selectedCellIndexPath] withRowAnimation:UITableViewRowAnimationFade];
//--- problematic code

    } else {
        self.selectedCellIndexPath = indexPath;
        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }
}

我的印象是局部变量tmp在这里应该有很强的引用,或者我不对?

顺便说一句,将代码更改为

NSIndexPath *tmp = self.selectedCellIndexPath;

或者改变

@[tmp, _selectedCellIndexPath]解决[NSArray arrayWithObjects:tmp,_selectedCellIndexPath,nil]问题。

这里出了什么问题的解释是什么?

4

2 回答 2

3

tmp是一个强有力的参考;默认情况下,本地人在 ARC 中。

鉴于您建议的两个修复完全应该是相同的结果(假设您没有覆盖 selectedCellIndexPath 的 setter 或 getter 来做一些奇怪的事情),我猜您已经找到了一个 ARC 错误。(我发现了其中的几个,所以我并不感到那么惊讶。)

尝试在打开僵尸的情况下运行您的代码。如果它告诉您您正在访问一个已释放的对象,我会说这是一个 ARC 错误。如果是这种情况,最好尝试创建一个简化的测试用例并提交一个错误。

编辑:

我认为这是一个 ARC 错误。问题似乎是在调用之前将对象存储到临时(堆栈上)缓冲区中,arrayWithObjects:count:但在该缓冲区中时它们不会保留。在您的代码中,这些对象在添加到缓冲区(在 -O1 或更高版本中)后会丢失其最后的强引用,因此您会获得早期的释放。这是一个更简单的测试用例,它通过导致对该临时缓冲区中的第一个对象的悬空引用导致崩溃(因为分配导致第一个对象被释放):

NSObject *foo = [[NSObject alloc] init];
@[foo, (foo = [[NSObject alloc] init])];
于 2013-03-03T15:59:23.803 回答
-1

您是否对您的代码进行了运行->分析?Clang 在指出潜在的 ARC 问题方面做得非常好(解释了为什么会出现问题)。将分析警告视为错误。

此外,如果您不希望 ARC 发布它,您的 'tmp' var 可能应该是 iVar。这可能并不总是最优雅的解决方案,但它告诉 ARC,“只要这个类实例存在,就保持这个值。”

您正在通过 iVar 引用访问 _selectedIndexPath,避免使用 getter 和 setter。这意味着您将跳过 ARC 管理的对保留、释放和自动释放的调用。

所以你可能应该使用'self'。

基本上,你不能总是预测 ARC 会做什么。它将尝试在每个方法结束时进行清理。所以有时你需要暗示它会通过创建一个属性来保留一些东西。有时我想念自己调用 alloc/release.... 有时大声笑

于 2013-03-03T16:12:34.253 回答