Hatena::Groupiphone-dev

Ni chicha, ni limona - 平均から抜けられない僕

2009-07-23

[iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中) 23:44  [iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中) - Ni chicha, ni limona - 平均から抜けられない僕 を含むブックマーク はてなブックマーク -  [iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中) - Ni chicha, ni limona - 平均から抜けられない僕  [iPhone] テーブルのスクロールが遅いので高速化に挑戦中(苦戦中) - Ni chicha, ni limona - 平均から抜けられない僕 のブックマークコメント

※@hiroaki310さんのレビューを反映させたコードもアップしました。本当にありがとうございます。

※@hirobeさんのコメントで有益な情報を得ました。ズルズルの原因はcellForRowAtIndexPath メソッド(+その後のセットアップ)の処理に時間がかかってしまうことのようです。コメントにあるように、ダミーのUIViewを用意して貼り付けておくと、だいぶん改善するようです。ありがとうございます!


現在作成中のアプリではテーブルビューを使う予定です。ところが実装して動かしてみると、スクロールさせたときの挙動がスムーズではありません。

本来なら「スルスル」とした感じでスクロールしてくれると思うのですが、実機上では「ズルッズルズルッ」といった具合に引っかかりがあり、イマイチ気持ちよくないUIになってしまっています。


テーブル内の各セルはビューコントローラの中で独自のものを作成しています。既存のものでは表示できない内容を表示させていることと、独自xibによるセルだと遅すぎて(ズ・・ズズズ・・・みたい)まともに動かないことで、その中間を狙って実装しました。

しかしそれでも遅い。


そこでテーブル高速化の常套手段:


  • セル内のビューを出来るだけ少なくする
  • セル内で半透明になっているものを不透明にする
  • セル内でのビューの重なりを避ける
  • テーブル動作中のデリゲートメソッドを出来るだけ減らす
  • テーブルの高さを高くする

などを試したのですが、どれも殆ど効果がありませんでした。


・・・で、「困った困った」とTwitterでつぶやいていたら、何人もの方*1にアドバイスをもらい、


 「Core Graphicsを使えばCPUの代わりにGPUで描いてくれるので、スクロールもスムーズになる」


といった趣旨の結論を得るに至りました。そこで教えてもらった参考サイトのプロジェクトファイル(リンク先)をベースに


  1. コントローラクラスの中でUITableViewCellクラスにビューを追加
  2. UITableViewCellクラスのサブクラスを作成してテーブルのセルに使用
  3. UITableViewCellクラスのサブクラスだけど、描画にはCoreGraphicsを使用

という3種類の方法でテーブルを実装し、動かしてみることにしました。


  サンプルプロジェクトをダウンロードする

   (修正前です。何が変わったかを比較したい方向け)

  サンプルプロジェクト(修正版)をダウンロードする

   (こちらが最新版。info.plistを変更して使ってください)


「これでうまく確認できる!」と思っていたのですが・・・

サンプルプログラムを実際に動かしてみると分かりますが、上記1-3のどれも殆ど同じでスベスベスクロールをしてくれました。orz

確かにCoreGraphicsが若干速いものの、殆ど誤差の範囲です・・・。じゃあどうして自作アプリのときはあんなにも遅いんだろう??


というわけで、今もって自アプリで遅い原因を調査中です。

何か分かったら、高速化できたらまた書きます。


長々と書いておきながらまだ解決していないという展開で、失礼しました。

*1:@takuma104さん、@cqa02303さん、@satokoさん、@hiroakiさん、@norio_nomuraさん、@onkn101さん、@khirohisさん、@kimadaさん、ありがとうございました。

@hiroaki310@hiroaki310 2009/07/24 00:43 ソース拝見しました。少し気になったことがありますので、以下に記させて頂きます。
メモリ管理上、不要なメモリの確保や解放し忘れ(リーク)が多いような気がします。

- FastTableViewCell.h
- プロパティをcopyで定義していますが、retainの方が早いのではないでしょうか?

- FastTableViewCell.m
- firstTextやlastTextプロパティへのセットはself.をつけないとダメじゃないでしょうか?
- firstTextやlastTextプロパティに s をセットする時にわざわざcopyする必要はないんじゃないでしょうか?
- drawAtPointする際に渡すUIFontを、わざわざstaticに持ってそれをセットする必要はないと思います。

- NormalTableViewCell.h
- プロパティをcopyで定義していますが、retainの方が早いのではないでしょうか?

- NormalTableViewCell.m
- firstTextLabelやlastTextLabelプロパティへの代入は self. をつけないとダメじゃないでしょうか?
- firstTextLabelやlastTextLabelをcontentViewにaddSubviewした後にリリースしていないようです。(この実装であれば、alloc/initWithFrameの後でautoreleaseした方がいいかもです。)
- UILableのfontプロパティは、それ自身がretainしてくれるので、わざわざUIFontをretainしたものをstaticに持ってそれをセットする必要はないと思います。
- 以下のような実装の方がいいと思います。
self.firstTextLabel = [[[UILabel alloc] initWithFrame:firstTextLabelRect] autorelease];
firstTextLabel.font = [UIFont systemFontOfSize:20];
[self.contentView addSubview:firstTextLabel];

- NormalView2Controller.m
- lastTextLabelをaddSubviewした後にreleaseしていないようです。

paellapaella 2009/07/24 11:22 コメント、というよりもレビューしていただいて恐縮です。

> FastTableViewCell.h
> - プロパティをcopyで定義していますが、retainの方が早いのではないでしょうか?
確かにそうですね。ここはオリジナルのファイルのままを使っていましたが、変えた方が良いですね。setFirst/LastTextメソッドは用意されていますので、
@property (nonatomic, retain) NSString *firstText;
としておきます(retainは警告つぶし)。そして、同セッターについては
[s retain]
[firstText release];
firstText = s;
[self setNeedsDisplay];
として、retain形式で保持するようにしました。コレによって、

> - firstTextやlastTextプロパティに s をセットする時にわざわざcopyする必要はないんじゃないでしょうか?
は解決出来たと思います。コピーは確かに不要ですね。

> - FastTableViewCell.m
> - firstTextやlastTextプロパティへのセットはself.をつけないとダメじゃないでしょうか?
これはセッター内でのことだと思いますが、ここでselfを付けてしまうとプロパティによって無限ループが発生してしまうので、あえて外してあると思っています。
勘違いしていたらすみません。

> - drawAtPointする際に渡すUIFontを、わざわざstaticに持ってそれをセットする必要はないと思います。
staticでUIFontを書いているのは、コンビニエンスメソッドのautoreleaseによるオーバーヘッドを避けてのものではないかな、と推測しています。オリジナルのままなので推測ですが。

> - NormalTableViewCell.h
> - プロパティをcopyで定義していますが、retainの方が早いのではないでしょうか?
そうですね。オリジナルとの比較がしやすいように合わせましたが、無意味でした。

@property (nonatomic, retain) UILabel *firstTextLabel;
@property (nonatomic, retain) UILabel *lastTextLabel;

に変更です。

> - firstTextLabelやlastTextLabelプロパティへの代入は self. をつけないとダメじゃないでしょうか?
ここは私のミスでした。付けます。

> - firstTextLabelやlastTextLabelをcontentViewにaddSubviewした後にリリースしていないようです。(この実装であれば、alloc/initWithFrameの後でautoreleaseした方がいいかもです。)
> - UILableのfontプロパティは、それ自身がretainしてくれるので、わざわざUIFontをretainしたものをstaticに持ってそれをセットする必要はないと思います。
ここはNormalTableViewCellセルクラスのメンバーであって、所有権は破棄していないことを明記したくて意図的に残しました。
あと、UIFontは確かにstaticで持つ必要は全然無いですが、オリジナルと合わせた方向で,というのを優先したのは事実です。
しかしdeallocメソッド内でreleaseされていないのは問題なので,リリースしておきます。

ということで、修正版を本記事中に改めてアップしておきます。
ありがとうございました。

@hiroaki310@hiroaki310 2009/07/27 11:17 >> - FastTableViewCell.m
>> - firstTextやlastTextプロパティへのセットはself.をつけないとダメじゃないでしょうか?
>これはセッター内でのことだと思いますが、...

すみません、これ、私の勘違いです。setterでしたね。大変、失礼しました。m(_ _)m

>> - firstTextLabelやlastTextLabelをcontentViewにaddSubviewした後にリリースしていないようです。
>ここはNormalTableViewCellセルクラスのメンバーであって、所有権は破棄していないことを明記したくて意図的に残しました。

そうでしたか。そういう意味では、firstTextLabelとlastTextLabelプロパティをretainじゃなくてassignで宣言しないとリークしちゃいそうですね。リファレンスカウンタが2個になると思うので。。(もし、self.を付けてセットするように変更する場合は、です。。)

色々と余計なコメントしてしまって逆にお時間とらせてしまったようで失礼しました。
これからもどうぞヨロシクお願いします。

paellapaella 2009/07/27 19:00 いいえ、こちらこそ色々と参考になったので助かりました。

> そうでしたか。そういう意味では、firstTextLabelとlastTextLabelプロパティをretainじゃなくてassignで宣言しないとリークしちゃいそうですね。リファレンスカウンタが2個になると思うので。。(もし、 self.を付けてセットするように変更する場合は、です。。)

そうですね。self.と付けるのと付けないのとで挙動が変わるコードはメンテナンス性が著しく落ちると思いますので、retainではなくassignにした方がいいですね。

いずれにせよ、助かっています。ありがとうございます。

hirogramhirogram 2009/07/28 22:24 わたしもズルズルスクロールで試行錯誤中です。
試した限りでは、ダミーのUIViewを用意して、Cellに張る予定のViewを先にダミーUIVewに張っておくとズルズルを回避できるようです。ただし、テーブルビュー自体の初期商事が遅くなるので、別スレッドでやるなどの対処が必要そうです。メモリ的にOKかNGかとかは未検証ですが。

paellapaella 2009/07/29 16:18 id:hirogramさん、貴重な情報を教えていただいて、ありがとうございます。

別のビューに貼り付けておくとズルズルが回避出来る、というのは朗報です。
これはテーブル内で使われる全セルの、全ビューということでしょうか。

余談ですが, UIへの処理を別スレッドでやるのは危険なので、初期処理が遅くなるのはしょうがないと諦めた方が良いかもです。

hirogramhirogram 2009/08/05 01:33 hirogramこと@hirobeです。
要は、cellForRowAtIndexPathが呼ばれるのが画面に出る直前なので、そこでの処理に手間取るとズルズルするようです。なので全ビューというよりは描画の遅そうなビューを対象とするとよいと思います。
セルについては全セルですが、データが多い場合は以下にあるようなページング処理と組み合わせるとよいかと。
http://d.hatena.ne.jp/KishikawaKatsumi/20090118/1232224534

heightForRowAtIndexPathがreload時に呼ばれるので、私はそこでビューをダミーUIViewに貼付けるなどしています。
別スレッドはご指摘の通り、うまくいきませんでした。

あと、グループを使うと一番上のセクションヘッダがスクロールに逆らおうとするアニメーション(?)で少し遅くなるような気がしています。セクションヘッダを使わないのも一つの手のようです。

paellapaella 2009/08/11 15:22 hirogramさん、返事が大幅に遅くなってしまってすみません。

色々とありがとうございます。ずいぶん掘り下げた調査をされているようで、とてもためになります。

表示のための準備処理が遅くなるとずるずるする、ということは果たしてセルの準備がボトルネックであるということですね。ここをできるだけ速くするように頑張ってみます。

それにしても、3.0だと幾つかの高速なスタイルが使えるので楽ちんになりましたね。互換性がない、というのが本当にネックですが・・・。

ChynaChyna 2011/09/16 14:13 Always the best content from these prodigious wrtires.

fhidfodmfhidfodm 2011/09/16 21:21 ACGU6E <a href="http://adezyoxivecp.com/">adezyoxivecp</a>

iuvtuyxwswziuvtuyxwswz 2011/09/17 00:48 g7bH92 , [url=http://aowajsamsbeg.com/]aowajsamsbeg[/url], [link=http://nhjcorppwbkv.com/]nhjcorppwbkv[/link], http://qmkvwdwikygg.com/

lfywczlfywcz 2011/09/18 23:32 ZCDUQA <a href="http://gmipmimfdzwd.com/">gmipmimfdzwd</a>

nsephopsfnsephopsf 2011/09/19 20:09 rCmbdQ , [url=http://hszuyduvmgjv.com/]hszuyduvmgjv[/url], [link=http://eycjthyxcyvk.com/]eycjthyxcyvk[/link], http://vfuxwdhqhvuf.com/

EstelaEstela 2013/01/22 21:48 Life is short, and this atrilce saved valuable time on this Earth.

lpvofflpvoff 2013/01/25 00:38 LeM0GH , [url=http://vcpbhgrhxamd.com/]vcpbhgrhxamd[/url], [link=http://rgiaxdceqhkn.com/]rgiaxdceqhkn[/link], http://hhnnjmulwtdh.com/

nzltynshrdqnzltynshrdq 2013/01/26 11:35 2MNhSa , [url=http://qrcauybfhfcl.com/]qrcauybfhfcl[/url], [link=http://yrqpsjnmrlxx.com/]yrqpsjnmrlxx[/link], http://jubcgaqhxmml.com/

ゲスト



トラックバック - http://iphone-dev.g.hatena.ne.jp/paella/20090723