web-dev-qa-db-ja.com

reloadRowsAtIndexPaths:withRowAnimation:アプリがクラッシュします

UITableViewで奇妙な問題が発生しました:reloadRowsAtIndexPaths:withRowAnimation:を使用して特定の行を再読み込みしましたが、一見無関係な例外でアプリがクラッシュします:NSInternalInconsistencyException-セクションに存在するよりも多くの行を削除しようとしました。 ==

私のコードは次のようになります:

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

そのreloadRowsAtIndexPaths:withRowAnimation:メッセージを単純なreloadDataに置き換えると、完全に機能します。

何か案は?

20
Anh Do

問題は、おそらくテーブルのサイズを変更したことです。たとえば、テーブルビューのソースデータを追加または削除したとします。

その場合、reloadDataを呼び出すと、セクションのサイズとそのセクションの数を含めて、テーブルが完全に再ロードされます。

ただし、_reloadRowsAtIndexPaths:withRowAnimation:_を呼び出すと、テーブルビューのパラメータは再ロードされません。これにより、次の問題が発生します。セルテーブルを再読み込みしようとしているときに、テーブルビューのサイズを確認し、変更されていることを確認します。その結果、クラッシュします。この方法は、セルのビューを再読み込みしたくない場合にのみ使用できます(たとえば、ラベルが変更された場合や、サイズを変更したい場合)。

ここで、テーブルビューから/テーブルビューにセルを削除/追加する場合は、次のアプローチを使用する必要があります。

  1. beginUpdatesのメソッドUITableViewを呼び出して、サイズが変更されることをテーブルに通知します
  2. メソッド- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animationを使用して新しい行を挿入することについて通知します
  3. メソッド- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animationを使用して行を削除することについて通知します
  4. endUpdatesのメソッドUITableViewを呼び出して、サイズが変更されたことをテーブルに通知します

お役に立てば幸いです

29
Nekto

次のコードが機能すると思います。

[self.tableView beginUpdates];

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

[self.tableView endUpdates];
9
Larry

この問題は、reloadRowsAtIndexPaths:withRowAnimation:を呼び出すブロックと、reloadDataを呼び出す並列スレッドが原因で発生していました。クラッシュは、numberOfRowsInSectionとnumberOfSectionsをサニティチェックしたにもかかわらず、reloadRowsAtIndexPaths:withRowAnimationが空のテーブルを見つけたことが原因でした。

例外が発生しても気にしないという態度でした。アプリ全体がクラッシュするよりも、アプリのユーザーとして一緒に暮らすことができる視覚的な破損。

これが私の解決策であり、喜んで共有し、建設的な批判を歓迎します。より良い解決策があれば、私はそれを聞きたがっていますか?

- (void) safeCellUpdate: (NSUInteger) section withRow : (NSUInteger) row {
    // It's important to invoke reloadRowsAtIndexPaths implementation on main thread, as it wont work on non-UI thread
    dispatch_async(dispatch_get_main_queue(), ^{
        NSUInteger lastSection = [self.tableView numberOfSections];
        if (lastSection == 0) {
            return;
        }
        lastSection -= 1;
        if (section > lastSection) {
            return;
        }
        NSUInteger lastRowNumber = [self.tableView numberOfRowsInSection:section];
        if (lastRowNumber == 0) {
            return;
        }
        lastRowNumber -= 1;
        if (row > lastRowNumber) {
            return;
        }
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
        @try {
            if ([[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] == NSNotFound) {
                // Cells not visible can be ignored
                return;
            }
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        }

        @catch ( NSException *e ) {
            // Don't really care if it doesn't work.
            // It's just to refresh the view and if an exception occurs it's most likely that that is what's happening in parallel.
            // Nothing needs done
            return;
        }
    });
}
5
Seoras

THIS IS OLD。使用しないでください。セルをUITextFieldを含む編集セルに変更するために、reloadRowsAtIndexPaths...を呼び出していたときにこの問題にぶつかりました。 。エラーは、テーブル内のすべての行を削除していることを示していました。問題を解決するために、次のものを削除しました。

[self.tableView beginUpdates];
NSArray *reloadIndexPath = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:section]];
[self.tableView reloadRowsAtIndexPaths:reloadIndexPath withRowAnimation:UITableViewRowAnimationFade];  
[self.tableView endUpdates];

と置き換えました

[self.tableView reloadData];
1
user216661

何度も試した結果、「reloadRowsAtIndexPaths」は、セルの内容を変更するだけで、セルを挿入または削除しない場合にのみ、特定の場所で使用できることがわかりました。包んでもどこでも使えない

_[self beginUpdates];
//reloadRowsAtIndexPaths
[self endUpdates];
_

それを使用できると私が見つけた場所は次のとおりです。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath - (IBAction) unwindToMealList: (UIStoryboardSegue *) sender

「viewDidLoad」や「viewDidAppear」から呼び出すなど、他の場所から試行しても、効果がないか(つまり、すでにロードされているセルの場合、リロードは効果がありません)、例外が発生します。

したがって、「reloadRowsAtIndexPaths」はそれらの場所でのみ使用するようにしてください。

1
Weidian Huang

私も同じ問題を抱えていました。私の場合;これは、別のビューコントローラーが既存のテーブルビューコントローラーをポップ/プッシュしてから[self.tableViewreloadRowsAtIndexPaths]関数が呼び出された場合にのみ発生していました。

reloadRowsAtIndexPaths呼び出しは、30を超える視覚的に複雑な行を持つテーブルビューで、さまざまな行を非表示/表示していました。この問題を修正しようとすると、テーブルビューアプリを少しスクロールしてもクラッシュしなかったことがわかりました。また、セルを非表示にしない場合(高さとして0を返すことにより)、クラッシュしませんでした

この問題を解決するには、「(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath」関数を変更し、行の高さとして少なくとも0.01を返しました。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
return rowModel.height + 0.01; // Add 0.01 to work around the crash issue.
}

それは私にとって問題を解決しました。

1
Oguz Demir

リロードする前にセルの可視性を確認する必要があります。ここにSwift 3コード:

        let indexPath = IndexPath(row: offset, section: 0)
        let isVisible = tableView.indexPathsForVisibleRows?.contains{$0 == indexPath}
        if let v = isVisible, v == true {
            tableView.reloadRows(at: [indexPath], with: .automatic)
        }
1
Bill Chan

TableViewにいくつかの変更を加えたため、アプリがクラッシュします。 tableViewにいくつかの行を追加または削除しました。したがって、View Controllerがモデルコントローラークラスにデータを要求すると、indexPathsに不一致があります。 indexPathsが変更後に変更されたため。

つまり、単に通話を削除するだけです

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

またはそれを置き換えます

[self.tableView reloadData];

ReloadDataを呼び出すと、セクションの数、各セクションの行の数がチェックされ、すべてがリロードされます。

0
iPhoneDeveloper