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にあります。

提案された2つの修正は、すべての権利で同じ結果になるはずです(selectedCellIndexPathのセッターまたはゲッターをオーバーライドして奇妙なことをしないと仮定すると)、ARCのバグを見つけたと思います。(私はこれらのいくつかを見つけたので、それは私をそれほど驚かせません。)

ゾンビをオンにしてコードを実行してみてください。割り当て解除されたオブジェクトにアクセスしていることが示されている場合は、ARCのバグだと思います。簡略化されたテストケースを作成して、その場合はバグを送信するとよいでしょう。

編集:

これはARCのバグだと思います。問題は、オブジェクトがが呼び出される前に一時的な(スタック上の)バッファに格納されているarrayWithObjects:count:が、そのバッファに保持されている間は保持されないことです。コードでは、これらのオブジェクトはバッファーに追加された後(-O1以上)、最後の強力な参照を失うため、早期のdeallocを取得します。これは、その一時バッファ内の最初のオブジェクトへのぶら下がり参照を引き起こすことによってクラッシュを引き起こすさらに単純なテストケースです(割り当てによって最初のオブジェクトが解放されるため):

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

コードに対して[実行]->[分析]を実行しましたか?Clangは、潜在的なARCの問題を(問題がある理由の説明とともに)指摘するのに非常に優れています。分析警告をエラーとして扱います。

また、ARCにリリースさせたくない場合は、'tmp'変数をiVarにする必要があります。これは常に最も洗練されたソリューションではないかもしれませんが、「このクラスインスタンスが存在する限り、この値を保持する」とARCに伝えます。

ゲッターとセッターを避けて、iVar参照を介して_selectedIndexPathにアクセスしています。これは、保持、解放、および自動解放するためにARC管理の呼び出しをスキップしていることを意味します。

したがって、おそらく「自己」を使用する必要があります。

基本的に、ARCが何をするかを常に予測できるとは限りません。すべてのメソッドの最後にクリーンアップを試みます。そのため、プロパティを作成することで何かが保持されるというヒントを与える必要がある場合があります。時々私はalloc/releaseを自分で呼び出すのを逃します....時々笑

于 2013-03-03T16:12:34.253 に答える