19

私はこれにやや行き詰まっています...どんな助けも大歓迎です。私はすでにこれをデバッグするのに多くの時間を費やしました。

UITableView提供するデータ ソースを使用していNSFetchedResultsControllerます。別のビュー コントローラーで、 を使用して新しいレコードを CoreData に挿入し[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:]、管理オブジェクト コンテキストを保存して、そのコントローラーを閉じます。非常に標準的なもの。

管理対象オブジェクト コンテキストの変更は、次のように受信されNSFetchedResultsControllerます。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
        [self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
        [self.tableView endUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];

            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

            break;

        case NSFetchedResultsChangeUpdate:
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

            break;

        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];

            break;
    }
}

ここで問題が発生します。これには時間がかかりすぎます (iPhone 4 では約 3 ~ 4 秒)。そして、セルのレイアウトの計算に時間が費やされているようです。

セル (カスタム サブクラスを含む) からすべてを削除し、そのまま残しましたUILabelが、何も変わりませんでした。次に、セルのスタイルを基本 (またはカスタム以外のもの) に変更すると、問題はなくなりました。新しいセルが即座に追加されます。

チェックを二重にしましたが、NSFetchedResultsControllerDelegateコールバックは 1 回だけ呼び出されます。それらを無視して実行すると[UITableView reloadSections:withRowAnimation:]、何も変わりません — それでも非常に遅いです。

デフォルトのセルスタイルでは自動レイアウトが無効になっているように思えます。これにより、非常に高速になります。しかし、その場合 — を押すとすべてがすばやく読み込まれるのはなぜUITableViewControllerですか?

その問題の呼び出しトレースは次のとおりです。 スタックトレース

問題は、ここで何が起こっているのかということです。セルのレンダリングが非常に遅いのはなぜですか?

更新 1

私が抱えている問題を説明する非常に単純なデモアプリを作成しました。ソースはこちら — https://github.com/antstorm/UITableViewCellPerformanceProblem

パフォーマンスの問題を感じるために、少なくとも画面一杯のセルを追加してみてください。

また、行を直接追加しても ([今すぐ挿入] ボタン)、速度が低下することはありません。

4

5 に答える 5

16

自動レイアウトがパフォーマンスに影響を与える可能性があることは事実です。ただし、ほとんどの場合、実際には目立ちません。複雑なレイアウトを取り除くことで意味のある違いが生じるエッジケースがいくつかありますが、それはここでは実際の問題ではありません。

アプリがこのように動作する理由についてはよくわかりませんが、少なくとも解決策があります。テーブル ビューが画面に表示されていない場合は、テーブル ビューの更新を行わないでください。これにより、この奇妙な動作が発生します。

これを行うには、たとえばself.tableview.window != nil、フェッチされた結果コントローラーのデリゲート メソッドで確認できます。次に、テーブル ビューが画面に表示される前にデータを更新するように、 [self.tableview reloadData]toを追加するだけです。viewWillAppear

それが役立つことを願っています。そして、誰かがこの奇妙な振る舞いについて良い説明を持っているなら、私に知らせてください:)

于 2013-06-09T19:31:08.047 に答える
2

iOS 7 の [table reloadData] で同じパフォーマンスが得られます。私の場合、この問題を解決して、セル構成コードを[cell layoutIfNeeded]次のコードに置き換えます。

[cell setNeedsUpdateConstraints];
[cell setNeedsLayout];

そして、セルを返します。何も問題ないようです。これが他の人が同じ問題を抱えているのを助けることができることを願っています.

于 2015-01-01T01:57:10.123 に答える
2

わかりました、アニメーションを犠牲にすることなく、ようやくこの問題を回避しました。UITableViewCell私の解決策は、 AutoLayout を無効にして別の Nib ファイルに のインターフェイスを実装することです。ロードには少し時間がかかり、サブビューを自分で配置する必要があります。

これを可能にするコードは次のとおりです。

- (void)viewDidLoad {
    [super viewDidLoad];

    ...        

    UINib *rowCellNib = [UINib nibWithNibName:@"RowCell" bundle:nil];
    [self.tableView registerNib:rowCellNib forCellReuseIdentifier:@"ROW_CELL"];
}

もちろん、セルのビューを含む RowCell.nib ファイルが必要です。

元の問題の解決策はありませんが (これは明らかにバグのようです)、私はこれを使用しています。

于 2013-06-12T14:08:05.263 に答える
0

uitableviewcell サブクラスで複雑な自動レイアウトを使用すると、同様の問題が発生しました。セルのレイアウトはサーバーからのデータに依存していますが、セルの状態の数は 6 に制限されています。したがって、dequeueReusableCellWithIdentifier (新しいセルが作成される) から nil を受け取るたびに、作成したばかりのセル (self.dynamicReusableIdentifier) に動的/カスタムの reuseIdentifier を設定します。reuseIdentifier ゲッターは、UITableViewCell サブクラス (ACellSubclass) でオーバーライドされます。

- (NSString*) reuseIdentifier {

    return self.dynamicReusableIdentifier;
}

self.dynamicReusableIdentifier 文字列の生成は、セル クラス (ACellSubclass) で定義された静的メソッド (configureDynamicReuseIdentifier) に基づいています。次に、 tableView:cellForRowAtIndexPathから返された正しい再利用可能な識別子を選択します。

cell = [tableView dequeueReusableCellWithIdentifier:[ACellSubclass configureDynamicReuseIdentifier:someData]];

再利用されたセルの静的サブビュー (ラベル、画像) は、自動レイアウト変更なしで更新されます。

于 2014-07-08T12:45:17.967 に答える