10 | 12月 | 2012 | HMDT Blog

カテゴリー : 2012年 12月10日

CATiledLayerやめました


CATiledLayerっていうレイヤーのクラスがある。主に巨大な画像、スクリーンの縦横4倍以上あるもの、を表示するときに使われる。画像をタイル状に分割して、必要なところだけ表示する事で、メモリの消費量を抑えているのだ。Appleのサンプルで積極的に登場している事もあって、よく使われているクラスだと思う。

でも、これ。使い込むと結構嫌なところが多くて。いちばん嫌なのは、タイル状の分割画像の読み込みをバックグラウンドのスレッドで行い、その生成と破棄の制御が全くできないこと。スレッドを立てるおかげでユーザインタフェースの操作は非常に滑らかなんだけど、いつ作られるか分からないし、作られたスレッドを中断させる事もできない。結果、主となるビューを頻繁に破棄するタイプのアプリだと(電子書籍とか)、結構な頻度でクラッシュが発生する。

どうにか折り合いをつけながらやってきたんだけど、iOS 6になったときかなり致命的に問題になったので、一念発起して使うのをやめる事にした。順次、独自のビュークラスへの置き換えを行っている。

独自のビュークラスっていってもたいした事やる訳じゃなくて、CATiledLayerがやっているのと同じ事を、自前でやるだけだ。画像分割したビュー(tiled viewって呼んでいる)を、画面の表示部分だけaddSubview:する。スクロールしたり、拡大縮小したりしたら、随時ビューの追加と削除を行う。

これを、メインスレッドだけで行っている。もちろん、サブスレッド使った方が動きが滑らかになるんだけど、現状のiOSデバイスの処理能力を持ってすれば、メインスレッドだけで全然いける。プログラミングモデルの単純さと安定性を考えれば、そっちの方が断然有利だ。ただ、表示する画像によってはやっぱりひっかかりが生じるので、そこはテクニックでカバーする。

基本的には力技で、それほど技巧的なものではない。ちょっと気をつけたいのは、tiled viewのtransformか。tiled viewはスクロールビューにaddSubview:するんだけど、普通にやるとスクロールビューのtransformにひきずられて、拡大したときにボケボケになってしまう。そこで、拡大率の逆数(2倍表示なら1/2、4倍表示なら1/4)のtransformを設定してやる。これでちゃんと拡大したときに高精度で表示されるようになる。