web-dev-qa-db-ja.com

iOS 6/7で「再利用されているテーブルセルのインデックスパスがありません」というメッセージの意味は何ですか?

IOS 6(およびiOS 7以降)でアプリのコンパイルを開始してから、このメッセージが表示され始めました。 UITableViewsがセルを管理する方法がiOS 6で異なることは知っていますが、機能し続けるためにコードを変更する必要はありません。しかし、私はこのメッセージが、私がまだ見ていない潜在的な問題を指しているのではないかと心配しています。誰もが光を当てることができますか?

57
Nathan Brown

IOS 7 GM/Releaseビルドなど、iOS 7ベータ5以降のログにこのエラーが表示されるようになりましたが、iOS 6または以前のiOS 7ベータのアプリでは発生しませんでした。多くの実験の後、私は原因を見つけました:

セクションヘッダービューにUITableViewCellオブジェクトを使用し、tableView:viewForHeaderInSection:でそれらを返していました。これは、特にiOS 5以降、Interface Builderを使用したStoryBoard内のプロトタイプテーブルビューセルとしてセクションヘッダービューを設計することが容易になったため、一般的な慣行のようです。

セクションヘッダービューに通常のUIViewサブクラスのみを使用するようにアプリを変更すると、エラーがなくなり、さらに重要なことに、テーブルビューがセクションヘッダーのランダムな削除を停止しました。

(iOS 7ベータ5以降)UITableViewは、ビュー階層内のすべてのUITableViewCellオブジェクトとそれぞれのインデックスパスのマッピングを内部的に維持しているようです。セクションヘッダー(またはフッターのテーブルビューヘッダー)にはインデックスパスがないため、これらのビューにUITableViewCellオブジェクトを使用すると、UITableViewCellが見つかったときにテーブルビューが混乱しますインデックスパスがないため、「テーブルセルのインデックスパスが再利用されていません」というエラーが発生し、運が悪ければ、テーブルビューにグリッチを表示します。

[〜#〜] update [〜#〜]:Apple Dev Forums、ここにありますそれに関するスレッド(私が始めた): https://devforums.Apple.com/message/882042#882042

そのスレッドで提案されているように、あまりリファクタリングしたくない場合は、UIViewの周りにUITableViewCellラッパーを作成し、それをセクションヘッダービューとして返すことができます。

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
[view addSubview:cell];

return view;

ただし、この「ラッパー」UIViewアプローチはAutoLayoutおよびデバイスの回転ではうまく機能しないため、UIViewサブクラスではなく、ヘッダーおよびフッターセルにUITableViewCellサブクラスを使用することをお勧めします。答えの主要部分で説明されているように。

132
mluisbrown

ラッパーを作成する代わりに、UITableViewCellのcontentViewを返します。

return cell.contentView;
41
mar-schmidt

私は同じ問題を抱えていましたが、問題を見つけるのに数時間かかりました。セルのセットアップ中に[textField becomeFirstResponder]を呼び出していたことがわかりました(ここではtextFieldはカスタムtableviewcellの一部でした)。 [textField becomeFirstResponder]inは、keyboardWillShow通知を送信します。これにより、tableviewが早まって自分自身をロードし、悪名高い「テーブルセルのインデックスパスが再利用されていません」メッセージが発生しました。 。

26
mpprdev

私が複数行のラベルを含んでいたため、受け入れられた答え(mluisbrown)に加えて、ヘッダーセルにautoresizingMaskを追加する必要がありました.

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
cell.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[view addSubview:cell];
return view;
16
Rob

これは、UIKitの内部バグです-Apple自身の開発フォーラムで述べられているように。 xcodeの新しいバージョンでは修正されていると思われますが、これを修正するバージョンに関する情報は見つかりませんでした。

8
diegoreymendez

私の以前の投稿(これは明らかにUIKitのバグであると述べた)に加えて、特定のケース(メッセージがテーブル上のいくつかの奇妙な視覚化グリッチに関連していた)の回避策を見つけることができました。

どうやら、カスタムセルのオーバーライドされた-(void)setEditing:animated:が戻るのに時間がかかりすぎたようです。

私の以前のコードは:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];
    [self someAdditionalCode];
}

次のように変更することで修正できました。

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];

    // DRM: we want to perform the actions from this block in the main thread, but
    // asynchronously to avoid excessive delays which were causing issues.
    //
    dispatch_async(dispatch_get_main_queue(), ^void()
    {
        [self someAdditionalCode];
    });
}
4
diegoreymendez

Resignfirstresponderが私の問題を解決した後にendupdatesを行う(カスタムセルにUITextFIeldがある)

-(void)textfieldEditDone
{
....

    [textField resignFirstResponder];
    [self.tableView endUpdates];
2
Daniel Åkesson

エラーメッセージが表示されるのと同じ問題がありました。私が見る限り、それはデリゲートプロトコルの一部としてテキストフィールドによって呼び出された関数からテーブルビューをリロードすることによって引き起こされます。すなわちtextFieldDidEndEditing-> [controller.tableview reload ...]

2
Dan

記録については、iOS 6で実行しているときにもこのメッセージが表示されました。継承またはインポートされたコードには次のようなものがあるようです。

(NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
    NSInteger rows = 0;
    if ([delegate respondsToSelector:@selector(numberOfItemsInSection:)]) {
        rows = [delegate numberOfItemsInSection:section];

        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

BeginUpdate:/ endUpdate:シーケンスが削除されると、問題は魔法のように消えました。

1
Fred The Bishop

これは明らかに古い質問ですが、これがiOS8 +でこの問題を未だに抱えている人の助けになることを願っています。これは、これがこの特定のエラーメッセージに対して出てくる一番の質問だからです。

PINRemoteImageを使用して、カスタムUITableViewCell内にあるUIImageViewに画像を非同期ダウンロードしました。

画像が読み込まれたら、行のサイズを適切に変更するために(自動レイアウトを使用した動的な高さセル)、私は以下を呼び出しました:

self.tableView beginUpdates;
self.tableView endUpdates;

「テーブルセルのインデックスパスが再利用されていません」というメッセージが表示され、アプリがクラッシュしていました。 PINRemoteImageManagerResultブロックはメインスレッドにあると思っていましたが、そうではないことが判明しました。したがって、メインスレッドで更新の開始/終了が呼び出されるようにすると、問題が修正されました。

dispatch_async(dispatch_get_main_queue(), ^(void){
                            [self.tableView beginUpdates];
                            [self.tableView endUpdates];
});
1
siburb

たぶんこれは誰かを助ける:私はかつて単一のTable Viewセルをリフレッシュしているときにこのエラーが発生しました。私は次のようなことをするつもりでした

NSIndexPath *reloadRow = [NSIndexPath indexPathForRow:1 inSection:2];
[self._mainTableView reloadRowsAtIndexPaths:@[reloadWebViewRow]
                           withRowAnimation:UITableViewRowAnimationFade];

しかし、誤って入力しました

NSIndexPath *reloadRow = [NSIndexPath indexPathForItem:1 inSection:2];

2つのインデックスパスの違いに注意してください。1つはindexPathForItem(間違った)で作成され、もう1つはindexPathForRow(正しい)で作成されます。これはすべて、tableViewの非常に奇妙な動作と見出しのエラーメッセージをもたらしました。

0
Tobias

Web呼び出しからのコールバックであるコードの一部内でUIを更新しようとしたときに、問題がトリガーされたようです。メインスレッドでUIの更新を強制することで解決しました。このようなコードを使用しました。

void runOnMainQueueWithoutDeadlocking(void (^block)(void)){
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

バックグラウンドWebコールの成功ブロック内で次のように呼び出します。

runOnMainQueueWithoutDeadlocking(^{
    [self.tableView beginUpdates];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
});
0

まだ別の条件...

これは、ヘッダーが必要ではなく、nilを返したときに発生しました。

修正:

func tableView(tableView: UITableView,
               titleForHeaderInSection section: Int) -> String? {
    return ""
}
0
SwiftArchitect

さて、私はこれを理解しようとして一日の大部分を使用したので、この代替説明が他の誰かの時間を節約することを願っています。

ロード時に、このメッセージ時々を提供していたテーブルビューがありました。ビューの読み込み中にコアデータオブジェクトのKVO通知が発生したことが原因であることが判明しました。 (変更を観察すると、コントローラーは問題のテーブルビューでreloadDataを呼び出しました。ビューの読み込みが完了するまでオブジェクトを観察しないことで修正しました(以前はアクセサーを介して割り当てられたオブジェクトの観察を開始しました)

TLDR:メインスレッド以外からデータをリロードしようとしているかどうかを確認します。

0
Jonathan Zhan