2013-06-05 15 views
17

私は多少このことに固執しています...どんな助けでも大歓迎です。私はすでにこれをデバッグするのに多くの時間を費やしました。AutoLayoutでUITableViewCellのパフォーマンスが悪くなる

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

変更は、その後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としましたが、何も変更されませんでした。次に、セルのスタイルをBasic(またはCustom以外のもの)に変更し、問題が消えた - 新しいセルが瞬時に追加されます。

私はチェックを2倍しており、NSFetchedResultsControllerDelegateコールバックは1回だけ呼び出されています。私がそれらを無視して[UITableView reloadSections:withRowAnimation:]を行うと、何も変わらない - それはまだ非常に遅いです。

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

はここでその問題のためのコール・トレースです: stack trace

そこで質問です - ここで何が起こっていますか?なぜ細胞がゆっくりとレンダリングされているのですか?

UPDATE 1

私は私がいる問題を示して非常に簡単なデモアプリケーションを構築しました。ここにソースがあります - https://github.com/antstorm/UITableViewCellPerformanceProblem

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

また、行を直接追加すると([今すぐ挿入]ボタン)、遅くなることはありません。

+2

あなたはカスタムセルに一意の識別子を割り当てて、再作成するのではなくデキューすることを訂正していますか? – James

+0

とセルにはどの自動レイアウトルールが指定されていますか? – Wain

+0

はい、私は一意の識別子を割り当て、 '[UITableView dequeueReusableCellWithIdentifier:forIndexPath:]'を使ってセルをデキューします。 –

答えて

2

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

ここでそれができるようにするコードです。もちろん

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    ...   

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

あなたのセルの景色をRowCell.nibファイルが必要になります。

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

+0

私はこの解決策を理解していません。自動レイアウトは無効になっていますか、あるいは何らかの形でパフォーマンスを得るためにシステムを騙しますか? –

+0

トリックは、各セルに対して別々のXibファイル(自動レイアウトを無効にする)を持つことです。そうすれば、全体的なインターフェースは自動レイアウトが有効になりますが、各セルは有効になりません。 –

+0

しかし、毎回、セルはペン先からロードされません。テーブルビューは、再利用可能なセルをメモリからデキューし、すでにペン先からロードされています。つまり、基本的にセルの自動レイアウトを無効にしています。それはどのように問題の解決策ですか? –

16

自動レイアウトでパフォーマンスが低下する可能性があります。しかし、ほとんどの場合、それは本当に顕著ではありません。レイアウトを複雑にするエッジケースがいくつかありますが、それを取り除くことで意味のある違いが生まれますが、それは実際には問題ではありません。

私はアプリケーションがそれがどんな風に動作しているのかについてはよく分かりませんが、少なくとも私には解決策があります。テーブルビューが画面に表示されていない場合、テーブルビューの更新はしないでください。この結果、この奇妙な動作になります。

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

希望に役立ちます。そして、もし誰かがこの奇妙な振る舞いの良い説明をしてくれたら、私に教えてください:)

+0

はい、 '[UITableView reloadData]'は実際に問題を解決しますが、アニメーションを取得せず、画面上のすべてのセルを再設定する必要があります。 '[UITableView reloadSections:withRowAnimation:]'を使うとテーブルデータをアニメーションでリロードできますが、元のメソッドと同じくらい遅いです。 –

+1

これは不思議に感謝しました。私はこの問題についてrdar:// 15175803を開いた。 –

+1

これも私の同様の問題を解決しました。私は 'viewWillAppear'に管理されたオブジェクトコンテキストを保存していました。 'viewDidAppear'への移動は、パフォーマンス上の問題を解決しました。画面上に表示されていないと、レイアウトが非常に遅くなります。 –

0

テーブルビューのセルで自動レイアウトを使用する場合は、それを実行可能にする方法があります。これは複数のステップからなるプロセスですが、そうすることでセル内の他のすべてのレイアウトに加えて、セルの垂直方向のサイズを自動レイアウトエンジンに設定させることができます。

あなたはここで詳細を見つけることができます:Using Auto Layout in UITableView for dynamic cell layouts & variable row heightsをあなたは私がUITableViewCellのサブクラスで、複雑な自動レイアウトを使用して同様の問題があった

0

のiOS 8の上にある場合、あなたが取ることができるいくつかのショートカットが含まれています。私のセルレイアウトはサーバーからのデータに依存しますが、セル状態の数は6に制限されています。したがって、dequeueReusableCellWithIdentifier(新しいセルが作成されます)からnilを受け取るたびに、作成したセル(self.dynamicReusableIdentifier)の動的/カスタムreuseIdentifierを設定します。 reuseIdentifierゲッターはUITableViewCellのサブクラス(ACellSubclass)でオーバーライドされる:

- (NSString*) reuseIdentifier { 

    return self.dynamicReusableIdentifier; 
} 

self.dynamicReusableIdentifier列の生成は、セルクラス(ACellSubclass)で定義された静的メソッド(configureDynamicReuseIdentifier)に基づいています。 のtableView; cellForRowAtIndexPath次いで

細胞= [:[ACellSubclass configureDynamicReuseIdentifier someDataが〕のtableView dequeueReusableCellWithIdentifier]から返された正しい再利用可能な識別子を取り出します

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

2

私は私の場合はiOSの7 で[テーブルreloadData]で同じperformenceを持って、私は[cell layoutIfNeeded]からフォローコードにセルのconfigureコードを置き換えるために、この問題を解決:

[cell setNeedsUpdateConstraints]; 
[cell setNeedsLayout]; 

し、その後復帰細胞。 Evevthingは大丈夫です。私はこれが他の人々が同じ問題を抱えているのを助けることができれば嬉しいです

+0

私のために働いた。簡単!ありがとう、 –

関連する問題